LENGTH_IN_CHAR和CHARSET的理解
1. LENGTH_IN_CHAR是什么
VARCHAR类型长度是否以字符为单位(N),可选值:Y/N,1/0。默认值为 0。可选参数。是初始化参数,一旦设置将不能修改。
1:是,设置为以字符为单位时,定义长度并非真正按照字符长度调整,而是将存储长度值按照理论字符长度进行放大。所以会出现实际可插入字符数超过定义长度的情况,这种情况也是允许的。同时,存储的字节长度 8188 上限仍然不变,也就是说,即使定义列长度为8188 字符,其实际能插入的字符串占用总字节长度仍然不能超过 8188。
0:否,所有 VARCHAR 类型对象的长度以字节为单位。
2.CHARSET是什么
字符集(0),可选值:0[GB18030],1[UTF-8],2[EUC-KR]。CHARSET=0代表使用GB18030,即一个中文两个字节。CHARSET=1代表使用UTF-8,即一个中文3个字节。默认为 0。可选参数。是初始化参数,一旦设置将不能修改。
3.测试实验
3.1 实验一(CHARSET=0 LENGTH_IN_CHAR=N)
SQL> CREATE TABLE TEST (ID INT,NAME VARCHAR(8));
操作已执行
已用时间: 20.546(毫秒). 执行号:59400.
SQL> INSERT INTO TEST VALUES (1,'甲乙丙');
影响行数 1
已用时间: 0.697(毫秒). 执行号:59401.
SQL> COMMIT;
操作已执行
已用时间: 2.728(毫秒). 执行号:59402.
SQL> INSERT INTO TEST VALUES (2,'甲乙丙丁');
影响行数 1
已用时间: 1.222(毫秒). 执行号:59403.
SQL> COMMIT;
操作已执行
已用时间: 1.866(毫秒). 执行号:59404.
SQL> INSERT INTO TEST VALUES (3,'甲乙丙丁戊');
INSERT INTO TEST VALUES (3,'甲乙丙丁戊');
[-6169]:列[NAME]长度超出定义.
已用时间: 1.314(毫秒). 执行号:0.
SQL> INSERT INTO TEST VALUES (3,'甲乙丙丁A');
INSERT INTO TEST VALUES (3,'甲乙丙丁A');
[-6169]:列[NAME]长度超出定义.
已用时间: 0.370(毫秒). 执行号:0.
SQL> SELECT DATA_LENGTH,NAME,LENGTH(NAME),LENGTHB(NAME) FROM TEST,DBA_TAB_COLUMNS
WHERE TABLE_NAME='TEST' AND COLUMN_NAME='NAME';2
行号 DATA_LENGTH NAME LENGTH(NAME) LENGTHB(NAME)
---------- ----------- -------- ------------ -------------
1 8 甲乙丙 3 6
2 8 甲乙丙丁 4 8
已用时间: 5.706(毫秒). 执行号:59407.
可以看出在字段长度为9时就报错超出长度,最多只能存储4个中文字符。
3.2 实验二(CHARSET=0 LENGTH_IN_CHAR=Y)
SQL> CREATE TABLE TEST (ID INT,NAME VARCHAR(8));
操作已执行
已用时间: 14.944(毫秒). 执行号:59400.
SQL> INSERT INTO TEST VALUES (1,'甲乙丙');
COMMIT;
影响行数 1
已用时间: 0.698(毫秒). 执行号:59401.
SQL> 操作已执行
已用时间: 4.695(毫秒). 执行号:59402.
SQL> INSERT INTO TEST VALUES (2,'甲乙丙丁');
COMMIT;
影响行数 1
已用时间: 0.473(毫秒). 执行号:59403.
SQL> 操作已执行
已用时间: 3.560(毫秒). 执行号:59404.
SQL> INSERT INTO TEST VALUES (3,'甲乙丙丁戊');
COMMIT;
影响行数 1
已用时间: 0.483(毫秒). 执行号:59405.
SQL> 操作已执行
已用时间: 1.993(毫秒). 执行号:59406.
SQL> INSERT INTO TEST VALUES (3,'甲乙丙丁戊己');
COMMIT;
影响行数 1
已用时间: 0.478(毫秒). 执行号:59407.
SQL> 操作已执行
已用时间: 3.593(毫秒). 执行号:59408.
SQL> INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚');
COMMIT;
影响行数 1
已用时间: 0.484(毫秒). 执行号:59409.
SQL> 操作已执行
已用时间: 5.337(毫秒). 执行号:59410.
SQL> INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛');
COMMIT;
影响行数 1
已用时间: 0.516(毫秒). 执行号:59411.
SQL> 操作已执行
已用时间: 3.734(毫秒). 执行号:59412.
SQL> INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛壬');
COMMIT;
INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛壬');
[-6169]:列[NAME]长度超出定义.
已用时间: 0.485(毫秒). 执行号:0.
SQL> 操作已执行
已用时间: 0.247(毫秒). 执行号:59414.
SQL> INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛B');
COMMIT;
INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛B');
[-6169]:列[NAME]长度超出定义.
已用时间: 0.452(毫秒). 执行号:0.
SQL> 操作已执行
已用时间: 0.212(毫秒). 执行号:59416.
SQL> SELECT DATA_LENGTH,NAME,LENGTH(NAME),LENGTHB(NAME) FROM TEST,DBA_TAB_COLUMNS
WHERE TABLE_NAME='TEST' AND COLUMN_NAME='NAME';
2
行号 DATA_LENGTH NAME LENGTH(NAME) LENGTHB(NAME)
---------- ----------- ---------------- ------------ -------------
1 8 甲乙丙 3 6
2 8 甲乙丙丁 4 8
3 8 甲乙丙丁戊 5 10
4 8 甲乙丙丁戊己 6 12
5 8 甲乙丙丁戊己庚 7 14
6 8 甲乙丙丁戊己庚辛 8 16
6 rows got
可以看出在字段NAME可以存储8个中文字符,实际最大存储长度为16,是长度定义的2倍。
3.3 实验三(CHARSET=1 LENGTH_IN_CHAR=N)
SQL> CREATE TABLE TEST (ID INT,NAME VARCHAR(8));
操作已执行
已用时间: 16.185(毫秒). 执行号:59400.
SQL> INSERT INTO TEST VALUES (1,'甲乙AB');
影响行数 1
已用时间: 0.751(毫秒). 执行号:59401.
SQL> COMMIT;
操作已执行
已用时间: 3.682(毫秒). 执行号:59402.
SQL> INSERT INTO TEST VALUES (2,'甲乙丙');
INSERT INTO TEST VALUES (2,'甲乙丙');
[-6169]:列[NAME]长度超出定义.
已用时间: 0.429(毫秒). 执行号:0.
SQL> SELECT DATA_LENGTH,NAME,LENGTH(NAME),LENGTHB(NAME) FROM TEST,DBA_TAB_COLUMNS
WHERE TABLE_NAME='TEST' AND COLUMN_NAME='NAME';
2
行号 DATA_LENGTH NAME LENGTH(NAME) LENGTHB(NAME)
---------- ----------- -------- ------------ -------------
1 8 甲乙AB 4 8
可以看出在CHARSET=1的情况下,一个中文占用3个字符,NAME只能存储两个中文两个英文字符,总长度8。
3.4 实验四(CHARSET=1 LENGTH_IN_CHAR=Y)
SQL> CREATE TABLE TEST (ID INT,NAME VARCHAR(8));
操作已执行
已用时间: 14.705(毫秒). 执行号:59400.
SQL> INSERT INTO TEST VALUES (1,'甲乙AB');
COMMIT;
影响行数 1
已用时间: 0.656(毫秒). 执行号:59401.
SQL> 操作已执行
已用时间: 4.171(毫秒). 执行号:59402.
SQL> INSERT INTO TEST VALUES (2,'甲乙丙');
COMMIT;
影响行数 1
已用时间: 0.435(毫秒). 执行号:59403.
SQL> 操作已执行
已用时间: 1.745(毫秒). 执行号:59404.
SQL> INSERT INTO TEST VALUES (3,'甲乙丙丁戊');
COMMIT;
影响行数 1
已用时间: 0.517(毫秒). 执行号:59405.
SQL> 操作已执行
已用时间: 3.732(毫秒). 执行号:59406.
SQL> INSERT INTO TEST VALUES (3,'甲乙丙丁戊己');
COMMIT;
影响行数 1
SQL> INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚');
COMMIT;
影响行数 1
已用时间: 0.437(毫秒). 执行号:59409.
SQL> 操作已执行
已用时间: 3.470(毫秒). 执行号:59410.
SQL> INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛');
COMMIT;
影响行数 1
已用时间: 0.446(毫秒). 执行号:59411.
SQL> 操作已执行
已用时间: 4.574(毫秒). 执行号:59412.
SQL> INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛壬');
COMMIT;
影响行数 1
已用时间: 0.438(毫秒). 执行号:59413.
SQL> 操作已执行
SQL> INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛壬癸');
COMMIT;
影响行数 1
已用时间: 0.534(毫秒). 执行号:59417.
SQL> 操作已执行
已用时间: 1.923(毫秒). 执行号:59418.
SQL> INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛壬癸A');
影响行数 1
已用时间: 0.412(毫秒). 执行号:59419.
SQL> COMMIT;
操作已执行
已用时间: 2.023(毫秒). 执行号:59420.
SQL> INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛壬癸AB');
影响行数 1
已用时间: 0.417(毫秒). 执行号:59421.
SQL> INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛壬癸ABC');
INSERT INTO TEST VALUES (5,'甲乙丙丁戊己庚辛壬癸ABC');
[-6169]:列[NAME]长度超出定义.
已用时间: 0.476(毫秒). 执行号:0.
SQL> SELECT DATA_LENGTH,NAME,LENGTH(NAME),LENGTHB(NAME) FROM TEST,DBA_TAB_COLUMNS
WHERE TABLE_NAME='TEST' AND COLUMN_NAME='NAME';
2
行号 DATA_LENGTH NAME LENGTH(NAME) LENGTHB(NAME)
---------- ----------- -------------------------------- ------------ -------------
1 8 甲乙AB 4 8
2 8 甲乙丙 3 9
3 8 甲乙丙丁戊 5 15
4 8 甲乙丙丁戊己 6 18
5 8 甲乙丙丁戊己庚 7 21
6 8 甲乙丙丁戊己庚辛 8 24
7 8 甲乙丙丁戊己庚辛壬 9 27
8 8 甲乙丙丁戊己庚辛壬癸 10 30
9 8 甲乙丙丁戊己庚辛壬癸A 11 31
10 8 甲乙丙丁戊己庚辛壬癸AB 12 32
可以看出,在CHARSET=1,可以存储3个中文字符的情况下,LENGTH_IN_CHAR=1,最终NAME字段实际存储长度为32,为定义长度的4倍。
4.结论
在使用GB18030作为字符集类型,且LENGTH_IN_CHAR为0时,只存储了4个中文字符,没有进行自动扩充。LENGTH_IN_CHAR为1时,实际最大存储长度为16,是长度定义的2倍;
在使用UTF-8作为字符集类型,且LENGTH_IN_CHAR为0时,只存储了两个中文字符加两个英文字符。LENGTH_IN_CHAR=1,实际最大存储长度为32,为定义长度的4倍。
如果需要考虑节省空间存储中文字符,可优先选择GB18030为字符集。
达梦社区地址 https://eco.dameng.com