纠正要求修改数据库NLS_LENGTH_SEMANTICS参数的错误要求

1、开发人员错误的要求

先看一封开发人员向某DBA提出的一个“要求修改数据库NLS_LENGTH_SEMANTICS参数”的邮件:

上面邮件,出于对隐私的保护,对发件人,收件人,数据库名称进行了隐涂。

邮件内容主要意思是:

(1)   源端和目标端数据库的字符集均为SIMPLIFIED CHINESE_CHINA.UTF8,但是源端数据库NLS_LENGTH_SEMANTICS参数的值为char,目标数据库NLS_LENGTH_SEMANTICS参数的值为byte

(2)   邮件中对知识错误的理解:由于源端数据库NLS_LENGTH_SEMANTICS参数的值为char(把1个汉字当成一个字节),目标数据库NLS_LENGTH_SEMANTICS参数的值为byte(把1个汉字占3个字节),所以,源端Varchar2(16)能存储16个汉字,而目标端Varchar2(16)即只能存5个汉字,导致源数据的数据无法插入到目标端数据库中去

(3)   邮件中错误的建议解决办法:将目标端数据库的NLS_LENGTH_SEMANTICS参数的值,改成与源端数据库NLS_LENGTH_SEMANTICS参数相同的值

2、知识的梳理

2.1 NLS_LENGTH_SEMANTICS参数的用途

NLS_LENGTH_SEMANTICS参数是一个专为创建CHAR和VARCHAR2两种字符型的列时,指定使用的字节长度,还是使用字符长度的定义方式,有byte和char两种值,默认为byte。

当设置该参数为BYTE时,定义CHAR列或VARCHAR2列采用字节长度方式;当设置该参数为CHAR时,定义CHAR列或VARCHAR2列采用字符长度的方式。该参数对于数据库中已经存在的列不具备任何用途,只是在创建表,或修改表的列时才具有意义。

2.2 字节长度与字符长度的区别

此章节从百度文库摘抄,原文地址为:http://baike.baidu.com/link?url=gtnaOI4rLZejxtdNISG3z8Vm1IpobqAB4nv3TRSnKh9RwTo2eR8eRkUWUUv00J7INVvGPQ2O51o-r77SfyIwT_

(1)ASCII码:

一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数,换算为十进制。最小值0,最大值255。如一个ASCII码就是一个字节。

(2)UTF-8编码:

      一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。

(3)   Unicode编码:

一个英文等于两个字节,一个中文(含繁体)等于两个字节。

(4)   符号:

一个英文标点占一个字节,一个中文标点占两个字节。举例:英文句号“.”占1个字节的大小,中文句号“。”占2个字节的大小。

3、邮件中对知识错误的理解

邮件中要求修改目标端数据库NLS_LENGTH_SEMANTICS参数,是完全错误的解决方案,之所以出现这样的情况,是因为此开发人员对NLS_LENGTH_SEMANTICS参数的理解不正确。

该开发人员,错误的将NLS_LENGTH_SEMANTICS参数理解成,只要该参数一改,数据库中所有的涉及CHAR和VARCHAR2两种字符型的列的长度类型都发生变化了。

其实不是,NLS_LENGTH_SEMANTICS参数的值,不对已经存在的列产生任何影响,只是在创建表中的列时,默认的指定列长度类型为byte还是char,如果在创建或修改表的列时指定了长度类型,完全覆盖NLS_LENGTH_SEMANTICS参数的值。

4、剖析问题的真正原因

其实,该开发人员所面对的真正问题原因,是源端表字段的长度类型与目标端表字段长度的类型不一致所致。

问题根本原因搞清楚了,解决方案就容易了,将目标端表的字段长度类型修改成与源端一样,不就解决了木。何必修改数据库参数还重启数据库的。

下面以三条create table的语句说清楚NLS_LENGTH_SEMANTICS参数的用途


(1)两条指定长度类型的SQL语句

create
table tab_t(t_name
varchar2(20
byte));

create
table tab_t(t_name
varchar2(20
char));

上面两条语句,唯一的不同,就是在指定列长度为20后,再指定长度的类型,类型的值不同。

(2)不指定长度类型的SQL语句

create
table tab_t(t_name
varchar2(20));

这条语句,在指定列的长度为20后,并未指定长度的类型,那它的类型会是什么呢,这个就是由NLS_LENGTH_SEMANTICS参数的值所决定了,该参数值可以在会话级设定。

5、测试验证

5.1 确认数据库的字符集类型

SQL> select *from nls_database_parameters t where t.parameter=‘NLS_CHARACTERSET‘;


PARAMETER                      VALUE

------------------------------   --------------------------------------

NLS_CHARACTERSET               AL32UTF8

5.2 创建列长度类型为byte的表并测试可插入数据长度

(1)查看NLS_LENGTH_SEMANTICS参数当前值

SQL> selectname,value from v$parameter where upper(name)=‘NLS_LENGTH_SEMANTICS‘;


NAME                 VALUE

------------------------------   -------------------------------

nls_length_semantics     BYTE

(2)创建带列长度类型为byte的表

SQL>create
table tab_t(t_name
varchar2(3));

(3)查看新创建的tab_t表的t_name列长度类型

SQL>select table_name,column_name,data_type,char_used
from dba_tab_columns where table_name=‘TAB_T‘


TABLE_NAME    COLUMN_NAME      DATA_TYPE    
 CHAR_USED

--------------------  -----------------------    -------------------------  -----------------------------

TAB_T                   T_NAME                    VARCHAR2        B

(4)插入英文字符串数据测试


$ export NLS_LANG=AMERICAN_AMERICA.UTF8

--注意上面这一条,设置客户端字符集很重要,如果环境变量有设置,此步可以跳过。如果发生复杂的字符集转换,一个中文汉字有可能会占用6个字节

SQL> insert into tab_t values (‘ZHO‘);

1 row created.

SQL> insert into tab_t values (‘ZHON‘);

insert into tab_t values (‘ZHON‘)

*

ERROR at line 1:

ORA-12899: value too large for column "SYS"."TAB_T"."T_NAME" (actual: 4,
maximum: 3)

从上面测试数据来看,插入三个英文字母成功,在插入四个字母的字符串时失败,提示实际长度为4,但maximum只有3

(5)   插入中文字符串数据测试


1)先计划一下“中”字占用几个字节

SQL> SELECT  LENGTHB(‘中‘) FROM DUAL;

LENGTHB(‘中‘)

-------------

3

2)插入一个中文汉字

SQL> insert into tab_t values (‘中‘);

1 row created.

3)插入两个中文汉字

SQL> insert into tab_t values (‘中国‘);

insert into tab_t values (‘中国‘)

*

ERROR at line 1:

ORA-12899: value too large for column "SYS"."TAB_T"."T_NAME" (actual: 6, maximum: 3)

插入两个中文汉字失败,实际长度为6,字段maximum只有3,在此验证确定,在UTF8下,一个中文汉字占3个字符。

5.3 将tab_t表的t_name列更改成char长度类型并做可插入长度测试

(1)将tab_t表的t_name列长度类型更改成char

SQL>alter
table tab_t modify
(t_name varchar2(3
char));

(2)验证修改结果

SQL> selecttable_name,column_name,data_type,char_used from dba_tab_columns wheretable_name=‘TAB_T‘ ;


TABLE_NAME    COLUMN_NAME      DATA_TYPE    
 CHAR_USED

--------------------  -----------------------    -------------------------  -----------------------------

TAB_T                    T_NAME                   VARCHAR2        C

(3)   插入两个中文汉字


SQL> insert into tab_t values (‘中国‘);

1 row created.

varchar2(3 char)插入两个中文汉字成功

6、小结

经过对开发人员的需求进行判断,以及纠正其对NLS_LENGTH_SEMANTICS参数用途错误的理解,用修改表字段长度类型的方式解决其面临的实际问题,避免了一次不必要的数据库重启,以及问题得到真正的解决。

本文作者:黎俊杰(网名:踩点),从事”系统架构、操作系统、存储设备、数据库、中间件、应用程序“六个层面系统性的性能优化工作

欢迎加入系统性能优化专业群,共同探讨性能优化技术。群号:258187244

时间: 2024-10-12 20:20:16

纠正要求修改数据库NLS_LENGTH_SEMANTICS参数的错误要求的相关文章

sqlserver 2008修改数据库表的时候错误提示“阻止保存要求重新创建表的更改”

当用户在在SQL Server 2008企业管理器中更改表结构时,必须要先删除原来的表,然后重新创建新表,才能完成表的更改,如果强行更改会出现以下提示:不允许保存更改.您所做的更改要求删除并重新创建以下表.您对无法重新创建的标进行了更改或者启用了“阻止保存要求重新创建表的更改”选项.如果要去掉此提示,可从“工具”菜单中选择“选项”,在“选项”对话框中,选Designers,选择“表设计器和数据库设计器”,清除“ 阻止保存要求重新创建表的更改”复选框. 转载请注明出处:http://www.cnb

ORACLE NLS_LENGTH_SEMANTICS 参数的用途

NLS_LENGTH_SEMANTICS参数是一个专为创建CHAR和VARCHAR2两种字符型的列时,指定使用的字节长度,还是使用字符长度的定义方式,有byte和char两种值,默认为byte. 当设置该参数为BYTE时,定义CHAR列或VARCHAR2列采用字节长度方式:当设置该参数为CHAR时,定义CHAR列或VARCHAR2列采用字符长度的方式.该参数对于数据库中已经存在的列不具备任何用途,只是在创建表,或修改表的列时才具有意义. NLS_LENGTH_SEMANTICS参数的值,不对已经

oracle初始参数设置错误导致数据库无法启动报ORA-00821的解决方案

今天为了修改数据库配置,将sga_max_size设置为了20G,但是sga_target没改,仍然为10G 结果改完后重启数据库就启动不了了,报ORA-00821错误 ORA-00821: Specified value of sga_target *** is too small, needs to be at least *** 而直接alter system set sga_target=20800M是不行的,因为数据库已经启动不了了,根本没法直接修改数据库参数,所以只能手动修改spfi

MySql重装以后,修改数据库路径,打开以前的数据库报Table 'XX库.XX表' doesn't exist错误的解决办法

因为mysql主流的数据库引擎有MyISAM和InnoDB两种, 如果是MyISAM,直接把以前数据库拷贝到修改后的路径是可以的 但是InnoDB因为存储结构不同,必须还得把备份的innodb数据库表“*.frm”文件和innodb数据“ibdata1”文件拷到修改后的合适路径 参考资料:http://www.bcty365.com/content-35-2928-1.html https://blog.csdn.net/dihuangtian01/article/details/5177353

Ubuntu 安装 mysql 并修改数据库目录

. . . . . 今天折腾了一下午的时间,恢复了无数次虚拟机快照,终于在 Ubuntu 上把 mysql 安装好了. mysql 是从官网下载的:mysql-server_5.7.16-1ubuntu12.04_i386.deb-bundle.tar 系统是 32 位 Ubuntu 12.04 LTS. 首先把下载好的 mysql-server_5.7.16-1ubuntu12.04_i386.deb-bundle.tar 放到虚拟机的 ~/tmp 目录下,然后进入该目录开始安装. [emai

mysql数据库的参数以及性能的调配

 mysql数据库的特性以及参数性能 一:mysql与其他数据库的比较 MySQL是一个关系型数据库管理系统,开发者为瑞典MySQL AB公司,现在已经被Sun公司收购,支持FreeBSD.Linux.MAC.Windows等多种操作系统与其他的大型数据库例如Oracle.DB2.SQL Server等相比功能稍弱一些 1.可以处理拥有上千万条记录的大型数据 2.支持常见的SQL语句规范 3.可移植行高,安装简单小巧 4.良好的运行效率,有丰富信息的网络支持 5.调试.管理,优化简单(相对其他大

SQL Server修改数据库对象所有者(Owner)浅析

在SQL Server数据库中如何修改数据库对象(表.视图.存储过程..)的所有者(Owner)呢?一般我们可以使用系统提供的系统存储过程sp_changeobjectowner来修改. 我们先看看sp_changeobjectowner在MSDN的文档介绍吧 更改当前数据库中对象的所有者.         重要提示:此存储过程只针对 Microsoft SQL Server 2000 中可用的对象进行.后续版本的 Microsoft SQL Server 将删除该功能.请避免在新的开发工作中使

修改oracle内存参数

Linux主机16g内存,修改oracle数据库内存参数: 1.编辑/etc/fstab文件:针对tmpfs行将defaults改成defaults,size=12g(千万注意格式,不能出现错误) 修改贡献内存参数后,reboot重启服务器. 2.sqlplus登录oracle数据库,备份参数文件: 以下语句备份参数文件(必须): SQL>create pfile='/u01/app/oracle/pfile20161625.ora' from spfile; 3.Show parameter

Err.number错误号和可捕获的 Microsoft access 数据库引擎和 DAO错误说明

错误码        信息2420        数字语法错误2421        日期语法错误2422        字符串语法错误2423        ‘.’.‘!’.或 ‘()’的使用无效2424        不认识的名称2425        不认识的函数名称2426        表达式中的函数不可用2427        对象没有值2428        与域函数一起使用的参数无效2429        In 运算符缺少 ()2430        Between 运算符缺少