NLS_LENGTH_SEMANTICS参数使用注意事项

浏览: 2342

从9i开始,oracle提供了NLS_LENGTH_SEMANTICS这个参数,其有两个取值,CHAR和BYTE。当为CHAR时字符类型的长度是按字符个数来计算,而不是按BYTE来计算,这在使用变长字符集(AL32UTF8)的情况下非常有用,因为一个字符所占用的字节数是不定的,就给我们准确估计字段长度(BYTE)带来不便。同时当为CHAR时,对那些采用7/8bit的字符集(US7ASCII/WE8MSWIN1252)来说也不会带来空间上的浪费。

下面就使用使用该参数需要注意的一些地方做出描述

1、该参数分为三个级别,分别是数据库、实例、会话三个级别

可以分别在NLS_DATABASE_PARAMETERS、NLS_INSTANCE_PARAMETERS、NLS_SESSION_PARAMETERS里查询到

数据库级的值在创意数据库时被指定,实例级的值可以通过修改init.ora/Spfile来指定,会话级的可以使用alter session来指定

 

2、实例/会话级的的参数只对其修改之后的对象(包括字段和pl/sql变量)产生作用,修改之前的维持不变。

可以使用ALTER SYSTEM SET NLS_LENGTH_SEMANTICS=CHAR scope=spfile;来修改实例级的参数值

注意,必须需要重启才会生效!(就算指定了scope=both)

 

该参数取值决定顺序

 

1、如果没有客户端(环境变量,后面会讲到)或者会话级指定该值,该参数由实例级的值决定(通过NLS_INSTANCE_PARAMETERS查询)

2、从10g开始,NLS_LENGTH_SEMANTICS可以在环境变量或者注册表中设定,一旦设定之后会话级的值默认为环境变量或注册表中的取值

(通过NLS_SESSION_PARAMETERS查询)

3、可以使用ALTER SESSION SET NLS_LENGTH_SEMANTICS=CHAR改变当前会话的取值。

 

 

其它注意事项

Oracle E-business Suite不支持该参数的CHAR语义

在11g以下的数据库中,不要在创建数据库时指定 NLS_LENGTH_SEMANTICS=CHAR,而应该使用 NLS_LENGTH_SEMANTICS=BYTE(或者不指定)来创建数据库,然后在修改ini.ora/spfile里改参数的值。否则会导致数据创建期间部分XDB和SYS的对象使用不支持的CHAR语义,产生错误,不过11.1.0.6之后已经得到解决。详见 Bug 5545716 和 Bug 4886376

数据库级取值为BYTE,实例级取值为CHAR 和 数据库级取值为CHAR,实例级取值为CHAR 是相同的,所以没必要纠结,详情可以参阅 Note 241047.1 The Priority of NLS Parameters Explained. 

你需要在BYTE语义下调用使用了STARTUP MIGRATE的脚本(比如patch脚本或者 $ORACLE_HOME/RDBMS/ADMIN 下的脚本(比如catalog.sql ))

If you run patch scripts or scripts from $ORACLE_HOME/RDBMS/ADMIN like catalog.sql use STARTUP MIGRATE; and run then the scripts. ( run them with NLS_LENGTH_SEMANTICS=BYTE )

 

* Oracle Text does NOT support instance wide NLS_LENGTH_SEMANTICS=CHAR If you are using Oracle Text then the database needs to be created and started with NLS_LENGTH_SEMANTICS=BYTE.
Using CHAR semantics on column definitions itself is supported however.Bug 4465964
This is not documented in the 10.2 docset, it is in the 11g doc: http://download.oracle.com/docs/cd/B28359_01/text.111/b28304/csql.htm#i997737 section "CHARSET COLUMN charset_column_name"

9i以下的客户端不能识别CHAR语义,当你用8i客户端去连接9i UTF8数据库时,数据库的VARCHAR2(10 CHAR)会以BYTE语义显示为VARCHAR2(30)

这样8i的的客户端才能插入不超过30byte的数据,鉴于此,当使用CHAR语义时,最好使用9i以上的客户端。

可以使用以下方法限定客户端版本为9及以上:

在10.1 中可以在init.ora中指定DB_ALLOWED_LOGON_VERSION=9

10.2及以上,在sqlnet.ora中指定SQLNET.ALLOWED_LOGON_VERSION = 9

注意:不要在10.2及以上使用DB_ALLOWED_LOGON_VERSION

 

设置之后,如果用8i及以下的客户端访问数据库会报ORA-28040: No matching authentication protocol错误

 

默认值

当NLS_LENGTH_SEMANTICS取值为BYTE时,默认为BYTE;当取值为CHAR时,默认为CHAR。

意思就是说,如果NLS_LENGTH_SEMANTICS=BYTE     char(10)实际上就是 char(10 byte)

如果NLS_LENGTH_SEMANTICS=CHAR     char(10)实际上就是 char(10 CHAR)

不管NLS_LENGTH_SEMANTICS取值为何,都可以在使用时显示的指定是按CHAR还是BYTE

例如,实例NLS_LENGTH_SEMANTICS=BYTE,在创建表时可以指定char(10 char)就可以使用char语义了

 

 

另外,对于单字节字符集编码来说,CHAR=BYTE

 

NLS_LENGTH_SEMANTICS对于属于SYS的表(对SYSTEM有效)无效,如下:

SQL> ALTER SESSION SET NLS_LENGTH_SEMANTICS=CHAR;
Session altered.
SQL> Create table sys.test1 (Col1 CHAR(20),Col2 VARCHAR2(100));
Table created.
SQL> Create table sys.test2 (Col1 CHAR(20 CHAR),Col2 VARCHAR2(100 CHAR));
Table created.
SQL> desc test1
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 COL1                                               CHAR(20 BYTE)
 COL2                                               VARCHAR2(100 BYTE)
SQL> desc test2
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 COL1                                               CHAR(20)
 COL2                                               VARCHAR2(100)

PL/SQL与NLS_LENGTH_SEMANTICS

存储过程和包里的在创建或者重新编译的时候会读取当前SESSION的NLS_LENGTH_SEMANTICS值,并存入代码中。考虑下面的问题

当前会话使用的是BYTE语义,你创建了一个存储过程,里面有一个变量的类型声明为CHAR(10),那么此时该变量实际为CHAR(10 BYTE),

有一天你把BYTE改成了CHAR,然后去调用该存储过程,你会发现报 ORA-06502 PL/SQL Numeric or value error错误,因为虽然环境使用的是CHAR语义,

但是存储过程里还是使用的BYTE语义,此时你需要重要编译该存储过程,它后重新读取当前SESSION的值,写入代码中。

鉴于此,建议在书写存储过程的时候显示声明其语义(CHAR(10 CHAR)),以免不必要的麻烦。

 

可以通过下在的SQL来查看现有存储过程使用的语义

SELECT C.owner
||'.'
|| C.name
||' - '
|| C.type
FROM DBA_PLSQL_OBJECT_SETTINGS C
WHERE C.NLS_LENGTH_SEMANTICS = 'CHAR'
-- to have a list of all using BYTE semantics use
-- WHERE C.NLS_LENGTH_SEMANTICS = 'BYTE'
-- to check only for a certain users use
-- and C.owner IN ('SCOTT')
ORDER BY C.owner,C.name
推荐 0
本文由 风在身后 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册