【发布时间】:2019-08-20 16:43:51
【问题描述】:
我的一个表中有一个类型为varchar2(2000) 的列,但这是否意味着2000 bytes?或2000 characters?因为我知道字节和字符之间是有区别的……
【问题讨论】:
我的一个表中有一个类型为varchar2(2000) 的列,但这是否意味着2000 bytes?或2000 characters?因为我知道字节和字符之间是有区别的……
【问题讨论】:
默认是你会话的NLS参数之一,即NLS_LENGTH_SEMANTICS。以下是我可以从我的会话中检查它的方法:
select value
from v$nls_parameters
where parameter = 'NLS_LENGTH_SEMANTICS'
;
VALUE
------
BYTE
您可以更改会话以更改值(或者您可以通过 SQL Developer 之类的图形界面进行操作)。如果您使用一个 ALTER SESSION 命令,也可以在您的LOGIN.SQL(或全局GLOGIN.SQL)中添加一个,如果您希望在启动会话时分配一个特定值。否则,当您开始一个新会话时,默认值将来自您的 SPFile(很可能)。
以下是我如何检查我的 SPFile 中的内容:
select value
from v$parameter
where name = 'nls_length_semantics'
;
VALUE
------
BYTE
我还可以更改我的系统以更改 SPFile 中的内容,但这是 DBA 的工作(我认为)。无论如何,它是可以改变的。
这类似于其他 NLS 参数 - 以 NLS_DATE_FORMAT 为例,其行为非常相似。
【讨论】:
USER_TAB_COLUMNS 视图后面的内容),它总是翻译varchar2 列宽到字节。因此,如果您当前的长度语义是CHAR,并且您创建一个列为VARCHAR2(20),并且您当前的字符集是一个四字节字符集(每个字符四个字节),那么 Oracle 将简单地存储该列是80 字节宽。它不会记住您将其声明为 20(CHAR,隐式)。
除了@mathguy 的回答,如果您有一个现有的表,您可以查询数据字典以查看您看到的大小(大概通过describe 或类似的)是字节还是字符:
create table t (col1 varchar2(2000 byte), col2 varchar2(2000 char));
select column_name, data_type, data_length, char_length, char_used
from user_tab_columns
where table_name = 'T';
COLUMN_NAME DATA_TYPE DATA_LENGTH CHAR_LENGTH CHAR_USED
----------- --------- ----------- ----------- ---------
COL1 VARCHAR2 2000 2000 B
COL2 VARCHAR2 4000 2000 C
其中char_used 是 C 表示字符限制,B 表示字节限制。
data_length 始终以字节为单位,因为这是真正的上限,并且有上限(在我的数据库中为 4000 - 可能是 32k;在 12c+ 中,MAX_STRING_SIZE 设置为 EXTENDED) - 所以即使我'已经说过col2 中允许使用 2000 个字符,如果我使用多字节字符,那么实际上我可能允许少于 2000 个字符,因为总字节数可能会尝试超过 4000。我实际上将 4000 视为数据长度对于声明大于 999 char 的任何内容,因为对于 AL32UTF8,它允许每个字符最多四个字节。
SQL*Plus 等中的describe 命令会显示原始大小,还会显示它是字节还是字符 - 但如果它与会话的NLS_LENGTH_SEMANTICS 设置匹配,则会忽略:
alter session set nls_length_semantics = 'BYTE';
desc t;
Name Null? Type
---- ----- -------------------
COL1 VARCHAR2(2000)
COL2 VARCHAR2(2000 CHAR)
alter session set nls_length_semantics = 'CHAR';
desc t;
Name Null? Type
---- ----- -------------------
COL1 VARCHAR2(2000 BYTE)
COL2 VARCHAR2(2000)
如果您未在 create 语句中指定 char 或 byte,该设置也用于默认语义,正如 @mathguy 解释的那样;但与大多数 NLS 设置一样,通常最好 (IMO) 明确声明它,这样就不会对将会发生的事情产生歧义或混淆。
【讨论】: