更改实时数据库中的
NLS_LENGTH_SEMANTICS
是个好主意吗?
数据库字符集使用多字节字符编码方案。因此,应用程序会出现无法重新创建的随机错误。在大多数情况下,ORA-06502: PL/SQL: numeric or value error
会升高。因此,为了解决这个问题,我们计划更改 NLS_LENGTH_SEMANTICS
参数值。对于应用程序,推荐的 NLS_LENGTH_SEMANTICS
设置为 CHAR
,并且在创建数据库实例时未设置为该值。
我的问题是,将值更改为 CHAR
会有帮助吗?或者使用 NLS_LENGTH_SEMANTICS = 'CHAR'
创建的新数据库实例并导出旧数据库并将其导入到新数据库有帮助吗?
NLS_LENGTH_SEMANTICS
使您能够使用字节或字符长度语义创建 CHAR
和 VARCHAR2
列。
现有列不受影响。
这意味着现有数据没有风险。
然而,
NLS_LENGTH_SEMANTICS
参数设置为 CHAR
可能会导致许多现有的安装脚本意外地创建具有字符长度语义的列,从而导致运行时错误,包括缓冲区溢出。
要解决它,您需要确保在运行任何 Oracle“内部”脚本(如补丁、升级等)时设置NLS_LENGTH_SEMANTICS=BYTE
。
在本文中,我提供了当字符长度语义设置为 BYTE 时 PL/SQL 缓冲区溢出和表插入错误的示例。在这些示例中,更改为 CHAR 语义会清除错误。
这里是缓冲区溢出,修复。
show parameter nls_length_semantics;
NAME TYPE VALUE
-------------------- ------ -----
nls_length_semantics string BYTE
declare
l_name varchar2(100) := 'What Are Em Dashes ( — ) And How Do You Use Them?';
l_sub varchar2(100);
l_buf varchar2(30);
begin
l_sub := substr(l_name, 1, 30);
dbms_output.put_line(l_sub);
dbms_output.put_line('lengthb: ' || lengthb(l_sub));
l_buf := l_sub;
end;
/
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
alter session set nls_length_semantics=char;
Session altered.
What Are Em Dashes ( — ) And H
lengthb: 32
这是一个列插入错误并修复:
show parameter nls_length_semantics;
NAME TYPE VALUE
-------------------- ------ -----
nls_length_semantics string BYTE
create table cathedrals(
name varchar2(30)
);
Table CATHEDRALS created.
insert into cathedrals (name) values (q'{Kölner Dom St. Peter und Maria}');
ORA-12899: value too large for column "USR"."CATHEDRALS"."NAME" (actual: 31, maximum: 30)
alter table cathedrals modify name varchar2(30 char);
Table CATHEDRALS altered.
insert into cathedrals (name) values (q'{Kölner Dom St. Peter und Maria}');
1 row inserted.
即便如此,您仍然容易受到运行时缓冲区溢出的影响。
show parameter nls_length_semantics;
NAME TYPE VALUE
-------------------- ------ -----
nls_length_semantics string BYTE
declare
l_name varchar2(30);
begin
select name into l_name from cathedrals;
end;
/
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
alter session set nls_length_semantics=char;
PL/SQL procedure successfully completed.
Oracle 声称将 nls_length_semantics 设置为 BYTE 会导致缓冲区溢出。事实上,我已经提供了三个示例,其中将 nls_length_semantics 更改为 CHAR 是解决此类错误的方法!
参数nls_length_semantics是在Oracle 9i中引入的。从 12c 开始,修改了手册以包含有关缓冲区溢出的警告。这个警告在博客中重复出现,包括 Don Burleson 的博客。
如果您没有在实例级别将 nls_length_semantics 设置为 CHAR,但您的应用程序可以存储多字节字符,那么请确保在创建表时为每一列显式声明 CHAR。
否则,多年来可能发生的情况是,随着外语名称(街道、城市、大学等)被添加到您的申请中,相同的错误出现在不同的地方。
最好在应用程序生命周期的早期将表中的 nls_length_semantics 设置为 CHAR。
原发布者问:“在实时数据库中更改 NLS_LENGTH_SEMANTICS 是个好主意吗?”做两件事: