Oracle NCHAR与NVARCHAR2 最大字符数和最大字节数

根据官方文档和实验测试整理一下常见问题以及相关结论,以NVARCHAR2为主。

 

一、 含义及用途

NCHAR和NVARCHAR2都是Unicode数据类型,存储Unicode字符数据。NCHAR和NVARCHAR2数据类型的对应的国家字符集(NLS_NCHAR_CHARACTERSET)只能是AL16UTF16或者UTF8。

  • NCHAR字段存储对应于国家字符集固定长度的字符串。
  • NVARCHAR2则存储可变长度字符串

NCHAR和NVARCHAR2均有最大字符长度和最大字节数的限制,这两个要求必须同时满足。下面分别来看

 

二、 最大字符长度

我们知道,对于char和varchar类型,是由nls_length_semantics参数的值来决定varchar(100)中的100指的字节数还是字符数(参考 聊聊字符串数据长度和nls_length_semantics参数),但对于NCHAR和NVARCHAR2来说,无论nls_length_semantics的值是什么,都相当于是char。因此NVARCHAR2(100)中的100一定是字符数。

When you create a table with an NCHAR or NVARCHAR2 column, the maximum size specified is always in character length semantics. Character length semantics is the default and only length semantics for NCHAR or NVARCHAR2.

Oracle NCHAR与NVARCHAR2 最大字符数和最大字节数_第1张图片

Oracle NCHAR与NVARCHAR2 最大字符数和最大字节数_第2张图片

最大字符长度可以定义为多少呢?

12c之前,取决于国家字符集设置

  • AL16UTF16:2000
  • UTF8:4000

从12.1开始,取决于两个设置 —— MAX_STRING_SIZE和国家字符集

  • 16383 if MAX_STRING_SIZE = EXTENDED and the national character set is AL16UTF16

  • 32767 if MAX_STRING_SIZE = EXTENDED and the national character set is UTF8

  • 2000 if MAX_STRING_SIZE = STANDARD and the national character set is AL16UTF16

  • 4000 if MAX_STRING_SIZE = STANDARD and the national character set is UTF8

根据这个定义,例如我们设置MAX_STRING_SIZE = STANDARD,NLS_NCHAR_CHARACTERSET=AL16UTF16,那最多就只能定义为NVARCHAR2(2000),即最多能存2000个字符;如果NLS_NCHAR_CHARACTERSET=UTF8,那最多能定义为NVARCHAR2(4000),即最多能存4000个字符。

Oracle NCHAR与NVARCHAR2 最大字符数和最大字节数_第3张图片

Oracle NCHAR与NVARCHAR2 最大字符数和最大字节数_第4张图片

 

三、 最大可储存字节数

对于NCHAR(无论版本),最大长度为2000字节,这个值是固定死的,不受其他参数影响。

对于NVARCHAR2,12c之前,最大长度为4000字节,这个值也是固定死的。

12.1开始,NVARCHAR2还受MAX_STRING_SIZE 参数影响,如果MAX_STRING_SIZE = STANDARD则与之前版本相同,最大长度为4000字节;如果MAX_STRING_SIZE = EXTENDED,最大长度为32767字节

即使按照前面的定义NLS_NCHAR_CHARACTERSET=UTF8,NVARCHAR2(4000)最多应该能存4000个字符,如果实际的数据大小超过了4000字节,就会遇到报错。由于UTF8中一个英文占1 byte,一个中文占3 byte,此时NVARCHAR2(4000)最多只能存1333个中文(即3999 byte)。

如果是用的NLS_NCHAR_CHARACTERSET=AL16UTF16,由于AL16UTF16无论中文英文每个都是占2 byte,此时NVARCHAR2(2000) 最多只能存2000个中/英文(即4000 byte)。

 

四、 客户端国家字符集NLS_NCHAR

如果你是用的NLS_NCHAR_CHARACTERSET=AL16UTF16,用客户端实际insert中文时应该会发现最多就只能插入1333个中文,再多就报错了,纯英文则没有这个限制,并且插入之后使用lengthb查看字节数,只是2666。很奇怪,中文字符数据并不符合第三节对AL16UTF16的规定,反而符合对UTF8的规定。

Oracle NCHAR与NVARCHAR2 最大字符数和最大字节数_第5张图片

Oracle NCHAR与NVARCHAR2 最大字符数和最大字节数_第6张图片

经过一番搜索,在文档 Selecting LENGTHB of an NVARCHAR2 does not return the byte length (文档 ID 2390023.1) 中找到了答案。

这个问题跟客户端国家字符集NLS_NCHAR的设置有关,NLS_NCHAR默认是UTF8,所以我们在客户端输入一个中文,实际上是占的3个byte。而输入1333个字符时,实际上已经占了3999 byte,所以再加中文就报错了。如果想要能输入2000个中文,应该要设置NLS_NCHAR环境变量为AL16UTF16(但测试的时候发现改了也没用,还没研究出来为啥)。

Oracle NCHAR与NVARCHAR2 最大字符数和最大字节数_第7张图片

为什么把1333个中文成功插入表后用lengthb查又变成了2666,应该是在插入时Oracle进行了字符集转换,把客户端的UTF8国家字符集转成了AL16UTF16,因此每个字符长度又变成了2 byte。

如果使用concat函数拼接我们前面输入的1000个中文变成2000个中文,会发现实际上是可以成功的,因为此时每个字符长度为2 byte,NVARCHAR2(2000)最多可以放2000个字符,最多刚好占4000 byte。

select length(v_byte),lengthb(v_byte) from t_byte;
insert into t_byte select concat(v_byte,v_byte) from t_byte where length(v_byte)=1000;

Oracle NCHAR与NVARCHAR2 最大字符数和最大字节数_第8张图片

 

参考

https://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#SQLRF30020

https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT1825

http://www.databases-la.com/?q=node/55

https://blog.darkthread.net/blog/nvarchar2-max-len-for-chinese/

https://oracle-base.com/articles/12c/extended-data-types-12cR1

https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/datatype-limits.html#GUID-963C79C9-9303-49FE-8F2D-C8AAF04D3095

Selecting LENGTHB of an NVARCHAR2 does not return the byte length (文档 ID 2390023.1)

你可能感兴趣的:(Oracle,排序规则&字符集)