ZHS16GBK字符集下面Oracle数据库varchar与nvarchar的验证

发布时间 2023-12-25 13:38:55作者: 济南小老虎

ZHS16GBK字符集下面Oracle数据库varchar与nvarchar的验证


背景

周末分析了 SQLServer mysql等数据库
想着继续分析一下oracle数据库
这边oracle使用的是ZHS16GBK的字符集.
所以比较特殊. 

还是建议得使用UTF-8字符集. 
能让系统干的活 就让系统干, 自己干国际化太费劲了. 

处理思路

使用 123 1234 12345 进行分割字符信息进行确认

部分SQL

alter session set container=ora19cpdb ;
create tablespace zhaobsh datafile '/opt/oracle/oradata/ORA19C/ORA19CPDB/zhaobsh.dbf' size 1m ;
create user zhaobsh identified by Test20131127 default tablespace  zhaobsh ; 


sqlplus zhaobsh/Test20131127@127.0.0.1/ora19cpdb
测试SQL为:
create table zhaobsh ( zhaobshvarchar varchar2(30), zhaobshnvarchar nvarchar2(30) ) ;
insert into zhaobsh values ('123abc','123abc') ;
insert into zhaobsh values ('1234赵abcd','1234赵abcd') ;
insert into zhaobsh values ('12345한국abcde','12345한국abcde') ;
insert into zhaobsh values ('123456한국abcdef',N'123456한국abcdef') ;
# 长度验证
insert into zhaobsh values ('1234567890123456789012345678901',N'1234567890123456789012345678901') ;
ASCII码 都是字节存储, 所以大小就是定义的 n 的数值。 
# 汉字验证
insert into zhaobsh values ('赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵',N'赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵') ;
varchar2 字段在GBK下面需要 除以 2
insert into zhaobsh values ('赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵',N'赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵赵') ;
nvarchar2 不需要除以 2  存储按照字符数进行存储

关于最大长度

之前总结过 oracle12c之前 ORACLE与SQLServer的varcahr和nvarchar都是 8000和 4000 的长度限制
但是在oracle12c 之后 oracle如果开启了一个 extended的模式后 
varchar的长度可以达到32k以上. 

但是需要注意 oracle12c 如果不开启参数, 也可以定义 varchar2(32000) 这样的大列了
但是如果不开启参数,会导致字符被截断

winhex的分析

先删除部分测试的数据 
然后copy出来文件.

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

0001FF60                                        31 32 33 34               1234
0001FF70   35 36 A3 BF A3 BF 61 62  63 64 65 66 1C 00 31 00   56??abcdef  1 
0001FF80   32 00 33 00 34 00 35 00  36 FF 1F FF 1F 00 61 00   2 3 4 5 6   a 
0001FF90   62 00 63 00 64 00 65 00  66 2C 01 02 0E 31 32 33   b c d e f,   123
0001FFA0   34 35 A3 BF A3 BF 61 62  63 64 65 18 00 31 00 32   45??abcde  1 2
0001FFB0   00 33 00 34 00 35 FF 1F  FF 1F 00 61 00 62 00 63    3 4 5   a b c
0001FFC0   00 64 00 65 2C 01 02 0A  31 32 33 34 D5 D4 61 62    d e,   1234赵ab
0001FFD0   63 64 12 00 31 00 32 00  33 00 34 8D 75 00 61 00   cd  1 2 3 4 u a 
0001FFE0   62 00 63 00 64 2C 01 02  06 31 32 33 61 62 63 0C   b c d,   123abc 
0001FFF0   00 31 00 32 00 33 00 61  00 62 00 63                1 2 3 a b c

ASCII分析

Oracle数据库应该是堆表
可以看到 ASCII的情况下
varchar2 是按照一个英文/数字一个字节进行存储的. 
nvarchar2 是按照两个字节一个汉字,英文, 数字进行存储的. 

06 31 32 33 61 62 63 
0C 00 31 00 32 00 33 00 61 00 62 00 63

这一点与SQLServer是一样的. 

中文分析

0A 31 32 33 34 D5 D4 61 62 63 64 
12 0031 0032 0033 0034 8D 75 0061 0062 0063 0064

按照之前的分析: 
赵	简体中文(GB2312、GBK)	gb2312	D5D4
赵	Unicode	               utf-16  758D
赵	Unicode (Big-Endian)   utf-16BE	8D75

明显可以看出 varcahr2 时使用的GBK编码
nvarcahr时使用的是utf-16 或者是相类似的编码格式. 
并且大端和小端有一些区别

韩文分析

0E 31 32 33 34 35 A3 BF A3 BF 61 62 63 64 65
18 0031 0032 0033 0034 0035 FF 1F FF 1F 0061 0062 0063 0064 0065
捍卫直接都是乱码
只不过在varcahr里面显示的是 A3 BF
在nvarcahr里面显示的是     FF 1F

加N验证

0E 31 32 33 34 35 A3 BF A3 BF 61 62 63 64 65
18 0031 0032 0033 0034 0035 FF 1F FF 1F 0061 0062 0063 0064 0065

发现加不加N 在Oracle里面是完全一样的ZHS16GBK字符集不太兼容国际化

总结

Oracle的ZHS16GBK 感觉不如 SQLServer的CHINESE_PRC_CI_AS
国际化的处理比较差
但是存储汉字时 ORACLE的varcahr和nvarchar与 SQLServer的逻辑比较相似. 

开源的PG/MySQL/达梦 自成一派. 
都是按照unicode 的编码进行排列的, 其实varchar和nvarchar在这三种数据库中是一样的.