天天看点

MySQL char与varchar非strict SQL模式下char(4)与varchar(4)存储对比

MySQL中char与varchar都是字符类型,但是其在存储,检索方式,最大允许长度,尾部空字符处理方面都有所不同。

MySQL char与varchar非strict SQL模式下char(4)与varchar(4)存储对比

char与varchar在声明时都可以指明一个长度值表示允许存储的最大字符数,例如:

char(10) varchar(255)

strict SQL模式在没被激活的情况下,Mysql允许存储大于char(varchar)声明的最大长度的字符,mysql会把字符自动裁剪到符合长度要求,并且给出警告,如果strict SQL模式被激活,对于非空字符的截断将会导致错误发生。

#char

char是固定字符类型,在声明的时候其大小就被确定,char允许声明的长度为【0,255】。如果实际存储的内容小于指定的长度,char类型的声明会导致值被以空格右填充到符合声明的长度后再存储,而在检索的时候,如果 PAD_CHAR_TO_FULL_LENGTHSQL模式没有被激活,内容右边的空格会被自动移除。

#varchar

varchar是可变字符类型,其大小随实际的存储内容而变化,varchar允许声明的长度为【0,65535】。但实际上varchar有效的长度声明受限于行大小65535bytes的限制,同时和所用的字符集也是有关系的。varchar存储数据的时候需要1byte或2byte附加于实际数据之前指示实际存储的数据长度。如果存储的数据不大于255bytes则用1byte,反之则用2bytes。varchar不会自动对存入其的数据进行空格填充,尾部空格在数据检索时也会被保留下来。

非strict SQL模式下char(4)与varchar(4)存储对比

Value CHAR(4) Storage Required VARCHAR(4) Storage Required
‘’ ’ '(4 spaces) 4 bytes ‘’ 1 byte
‘ab’ 'ab ’ 4 bytes ‘ab’ 3 bytes
‘abcd’ ‘abcd’ 4 bytes ‘abcd’ 5 bytes
‘abcdefgh’ ‘abcd’ 4 bytes ‘abcd’ 5 bytes

#尾部空字符在查询时造成的影响

由于尾空格在char类型中检索数据时会被自动移除的原因,给定的值,存储于char,varchar后再分别提取可能会发现其内容不一致。

mysql> CREATE TABLE vc (v VARCHAR(4), c CHAR(4));Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO vc VALUES ('ab ', 'ab ');Query OK, 1 row affected (0.00 sec)
mysql> SELECT CONCAT('(', v, ')'), CONCAT('(', c, ')') FROM vc;
+---------------------+---------------------+
| CONCAT('(', v, ')') | CONCAT('(', c, ')') |
+---------------------+---------------------+
| (ab ) | (ab) |
+---------------------+---------------------+
1 row in set (0.06 sec)
           

MySQL中所有的校对规则都是PADSPACE类型的,所以在比较时候的时候尾部空字符是不影响比较(不包括LIKE)结果的。该规则对所有MySQL版本都适用,也和SQL模式没关系。

mysql> CREATE TABLE names (myname CHAR(10));Query OK, 0 rows affected (0.03 sec)
mysql> INSERT INTO names VALUES ('Monty');Query OK, 1 row affected (0.00 sec)
mysql> SELECT myname = 'Monty', myname = 'Monty ' FROM names;
+------------------+--------------------+
|myname = 'Monty' | myname = 'Monty '  |
+------------------+--------------------+
| 1 | 1 |
+------------------+--------------------+
1 row in set (0.00 sec)
mysql> SELECT myname LIKE 'Monty', myname LIKE 'Monty ' FROM names;
+---------------------+-----------------------+
| myname LIKE 'Monty' | myname LIKE 'Monty ' |
+---------------------+-----------------------+
| 1 | 0 |
+---------------------+-----------------------+
1 row in set (0.00 sec)
           

鉴于上述原因,在尾部的空字符会被自动剥离截断以及比较时忽略尾部空字符的情况下,对于有unique约束的列,同时插入’a’, 'a '将会导致duplicate-key的错误。