您的位置:首页 > 产品设计 > UI/UE

OGG: NLS_LENGTH_SEMANTICS报错信息ora-12899 value too large for column

2013-05-28 11:42 746 查看

1
故障记录

报告人/单位

甲骨灰

报告日期

04月

故障发生时间

故障解决时间

故障周期

故障现象描述:
某系统容灾对端ogg复制软件复制进程经常Abended。
报错信息ora-12899 value too large for column 。

2
故障分析与处理

2.1
故障产生环境记录

故障类别

硬件

硬件[UNIX主机
磁盘阵列 磁带库
网络设备]

软件

软件[ 操作系统
数据库 其它(请注明) ]

设备序列号/软件版本

Oracle 10.2.0.4

其它

2.2
系统应急处理措施

保证业务正常运行已采取的应急处理措施(请注明处理的时间及手段)

1、修改无法插入字符字段的单位从byte到char.

alter table tab_name modify col_name varchar2(char_length char);

2.3
日志分析、故障原因定位和处理措施

知识背景:

Oracle的这个参数nls_length_semantics有byte和char两种取值,数据库可以使用这两种单位创建char或varchar2类型的数据库表列。二者的区别是一个按照字符存放,一个按字节存放。

对使用UTF-8字符集的数据库,一个汉字如果按照字节(byte)存放,会占用3个字节(byte),按字符(char)存放一个汉字只占用一个字符(char)。

NLS_LENGTH_SEMANTICS

PropertyDescription
Parameter typeString
Syntax
NLS_LENGTH_SEMANTICS =
string

Example:
NLS_LENGTH_SEMANTICS = 'CHAR'

Default value
BYTE
Modifiable
ALTER SESSION
Range of values
BYTE | CHAR
NLS_LENGTH_SEMANTICS
enables you to create
CHAR
and
VARCHAR2
columns
using either byte or character length semantics. Existing columns are not affected.
NCHAR
,
NVARCHAR2
,
CLOB
, and
NCLOB
columns
are always character-based. You may be required to use byte semantics in order to maintain compatibility with existing applications.
NLS_LENGTH_SEMANTICS
does not apply to tables in
SYS
and
SYSTEM
.
The data dictionary always uses byte semantics.
译:

NLS_LENGTH_SEMANTICS
使您能够创建使用字节或字符长度语义的
CHAR
VARCHAR2
列。现有列不受影响。
NCHAR
NVARCHAR2
CLOB
NCLOB
列总是基于字符。您可能需要使用字节语义,以保持与现有应用程序的兼容性。
NLS_LENGTH_SEMANTICS
不适
SYS
SYSTEM
表。数据字典总是使用字节语义。

1、检查数据库的nls_length_semantics参数值是byte还是char,

select value from v$nls_parameters where parameter=’NLS_LENGTH_SEMANTICS’;

注意从:sys.nls_database_parameters里面查到的结果并不是真正的值,使用以上语句查。

说明:某系统对端在建库之后应该调整为Char,而实际上未调整,还是默认的byte类型。

这样,如果要存储的字符串全部是英文字母或数字,那么两者还看不出区别,如果字符串中有汉字,例如“中国”,在定义字段长度的时候,我们定义的是varchar(2),这个NLS_LENGTH_SEMANTICS参数如果为char,那么可以装得下,如果是byte,就装不下了。

当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语义了。

分析:

这个值修改后只对新生成的数据生效,对原有的数据无影响,因此需要想办法把它调整过来:

修改数据库的nls_length_semanitcs参数:该参数有三个级别,分别是database,instance,session。可以分别在nls_database_parameters,nls_instance_parameters,nls_session_parameters里查询到。
数据库级的值在创建数据库时被指定,实例级的值可以通过修改数据库参数pfile或spfile来指定,会话级的可以使用alter session来指定。
实例和会话级的参数只对修改之后的对象(包括字段和plsql变量)产生作用,修改之前的维持不变。具体命令如下:

alter system set nls_length_semantics=char scope=both;

注意:此参数必须重启生效,即使可以使用scope=both来修改

3、由于修改nls_length_segmantics参数后只对修改之后的对象(包括字段和plsql变量)产生作用,修改之前的维持不变,所以还需要对已经存在的对象进行修改。

A、对于字段修改语句如下:

alter table tab_name modify col_name varchar2(char_length char);
也可使用下面语句批处理执行(但需要注意在系统空闲的时候使用,对于系统复制需要停止目标端的复制进程):

select 'alter table '||owner||'.'||table_name||' modify '||column_name||' VARCHAR2('||char_length||' char);'

from dba_tab_columns s

where owner IN ('AMBER','KBSD','OWF_MGR','SGPM','SGPM_API','SGPM_OUT','WF_AMBER')

and char_used='B'

and exists(select 1 from dba_objects t where t.OWNER=s.OWNER and t.OBJECT_NAME=s.TABLE_NAME

and t.OBJECT_TYPE='TABLE');

B、对于plsql变量(procedure,package,type等),直接重新编译就可以了,批处理语句如下:

select 'alter '||type||' '||name||' compile;'

from dba_plsql_object_settings
s

where s.OWNER in ('AMBER','KBSD','OWF_MGR','SGPM','SGPM_API','SGPM_OUT','WF_AMBER')

and nls_length_semantics='BYTE' ;

注意:修改表定义后需要重现编译所有失效对象!

查看所有失效对象并重新编译

SELECT 'ALTER '||

(case OBJECT_TYPE when 'PACKAGE BODY' then 'PACKAGE' else OBJECT_TYPE end) ||

' '||o.owner||'.'||

o.object_name||

(case OBJECT_TYPE when 'PACKAGE BODY' then ' COMPILE BODY;' else ' COMPILE;' end)

FROM DBA_OBJECTS
o

WHERE STATUS <> 'VALID'
and o.object_type<>'SYNONYM'

order by 1;

3
故障责任定位

4
改进建议或其它说明

建议或相关说明(如是否需要软件升级或打补丁进行改进等等。)

本次故障建议:
1、在11G以下的数据库中,不要在创建数据库时指定nls_length_semantics=CHAR(默认安装是byte),应该在创建实例后修改nls_length_semantics参数,再导入应用的数据。这是因为部分xdb和sys用户的对象不支持 CHAR语义,会产生错误,不过11.1.0.6之后已经得到解决。详见Bug 5545716 和 Bug 4886376

2、9i以下的客户端不能识别CHAR语义,当你用8i客户端去连接9i UTF8数据库时,数据库的VARCHAR2(10 CHAR)会以BYTE语义显示为VARCHAR2(30) ,这样8i的的客户端才能插入不超过30byte的数据,鉴于此,当使用CHAR语义时,最好使用9i以上的客户端。

3、存储过程或包在创建或者重新编译的时候会读取当前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)),以免不必要的麻烦。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: