MySQL CHAR和VARCHAR区别
作者:空中蘑菇云
MYSQL中char和varchar是存储较短字符串常用的两种数据类型,用法比较相似,需要在使用时都需要指定长度用来表示表示可以容纳的最大字符数量。虽然这两种数据类型有很多相似之处,但是在数据长度、数据写入读取、存储引擎存储上都有比较大的差异。
使用形式
char和varchar的最简单的使用方式是通过类型后面跟长度,确定该字段最大存储的字符个数,举例如下,创建一张表,表里面两个字段分别是CHAR和VARCHAR,设置的长度是6,也就十说最大存储的字符个数为6:
create table chars(c CHAR(6), vc VARCHAR(6));
简述中描述过1-2bytes存储数据长度,具体的存储规则可以描述如下,这里我们引入三个符号,分别是列的设定长度(M),字符集的长度(C),数据的实际长度(L),具体如何存储长度信息,大体可以描述如下:
如果M * C <= 255,使用1bytes表示长度。
如果M * C > 255,使用两个字节表示长度,但是有下面两种场景:
- 当L <= 127时,也就时长度可以用 0111111表示时,使用一个字节表示长度
- 当L > 127 时,使用两个字节表示长度。
差异
char和varchar在声明形式相似,两种数据类型的差异可以总结如下:
长度差异
char支持的存储的最大数据长度是0-255,varchar支持存储的的数据范围0-65535(受限于表行的长度限制65535bytes及相关字符集)。
char类型测试:
# char创建表 mysql> create table chars_c_256(c CHAR(256)); ERROR 1074 (42000): Column length too big for column 'c' (max = 255); use BLOB or TEXT instead mysql> create table chars_c_0(c CHAR(0)); Query OK, 0 rows affected (0.00 sec) mysql> create table chars_c_1(c CHAR(1)); Query OK, 0 rows affected (0.00 sec) mysql> create table chars_c_255(c CHAR(255)); Query OK, 0 rows affected (0.01 sec)
varchar类型测试:
# 查看mysql server默认字符集 show variables like '%character_set_server%'; mysql> show variables like '%character_set_server%'; +----------------------+---------+ | Variable_name | Value | +----------------------+---------+| character_set_server | utf8mb4 | +----------------------+---------+ 1 row in set (0.00 sec) # 由于server端使用的字符集是utf8mb4,utf8mb4最大占用4bytes,单行最大字节数是65535bytes,因此整行可以完整存储的最大字符数16383 # varchar创建表 mysql> create table vchars_c_16384(c VARCHAR(16384)); ERROR 1074 (42000): Column length too big for column 'c' (max = 16383); use BLOB or TEXT instead mysql> create table vchars_c_16383(c VARCHAR(16383)); Query OK, 0 rows affected (0.01 sec) mysql> create table vchars_c_0(c VARCHAR(0)); Query OK, 0 rows affected (0.01 sec)
数据写入读取差异
使用char和varchar时需要指定长度,在非严格sql模式下,超过设定长度的数据会被截断,并发出一个警告,严格模式下超过设定长度的数据会报错。于此同时,每一列都会在行格式中使用1-2bytes用来表示数据长度,如果数据长度没有超过255bytes使用一个字节表示,如果超过255bytes使用2bytes表示长度。,如果数据长度超过设定长度,那么数据会被截断,严格sql模式时,sql会报错,非严格模式时,sql会警告,如果被截掉的内容时空格char和varchar的表现形式不太一样,varchar无论在任何sql模式下都会发出警告,而char在严格sql模式才会发出警告,具体可以测试如下:
# 查看当前表模式 mysql> show variables like "sql_mode"; +---------------+-----------------------------------------------------------------------------------------------------------------------+ | Variable_name | Value | +---------------+-----------------------------------------------------------------------------------------------------------------------+| sql_mode | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION | +---------------+-----------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) # 可以看到STRICT_TRANS_TABLES模式,为支持事务性的表开启严格sql模式,因为我这边使用的存储引擎是innodb,因此会默认开启严格sql模式 # 截断空格的场景 mysql> insert into chars (c, vc) values('123456 ', '123456'); Query OK, 1 row affected (0.00 sec) mysql> insert into chars (c, vc) values('123456', '123456 '); Query OK, 1 row affected, 1 warning (0.00 sec) # 截断字符的场景 mysql> insert into chars (c, vc) values('abcdef', 'abcdefg'); ERROR 1406 (22001): Data too long for column 'vc' at row 1 mysql> insert into chars (c, vc) values('abcdefg', 'abcdef'); ERROR 1406 (22001): Data too long for column 'c' at row 1 # 关闭严格sql模式 mysql> SET sql_mode = '';Query OK, 0 rows affected (0.00 sec) mysql> show variables like "sql_mode"; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | sql_mode | | +---------------+-------+ 1 row in set (0.00 sec) # 截断空格的场景 mysql> insert into chars (c, vc) values('abcdef ', 'abcdef'); Query OK, 1 row affected (0.00 sec) mysql> insert into chars (c, vc) values('abcdef', 'abcdef '); Query OK, 1 row affected, 1 warning (0.00 sec) # 截断字符的场景 mysql> insert into chars (c, vc) values('abcdef', 'abcdefg'); Query OK, 1 row affected, 1 warning (0.00 sec) mysql> insert into chars (c, vc) values('abcdefg', 'abcdef'); Query OK, 1 row affected, 1 warning (0.00 sec)
char普遍可以理解是固定长度的string,varchar可以是设定长度内的可变长度的string,char在存储时如果存储的数据长度不够设置长度,会在后数据右边填充空格,检索的时候填充数据会被移除。
varchar在写入时如果后面有空格,会连同空格一块写入,如果char后面有空格会被截断掉,具体可以测试如下:
insert into chars (c, vc) values('2 ', '2 '); mysql> select CONCAT('(', c, ')'), CONCAT('(', vc, ')') from chars where c = '2 '; Empty set (0.00 sec) mysql> select CONCAT('(', c, ')'), CONCAT('(', vc, ')') from chars where c = '2'; +---------------------+----------------------+| CONCAT('(', c, ')') | CONCAT('(', vc, ')') | +---------------------+----------------------+| (2) | (2 ) | +---------------------+----------------------+ 1 row in set (0.00 sec) mysql> select CONCAT('(', c, ')'), CONCAT('(', vc, ')') from chars where vc = '2'; Empty set (0.00 sec) mysql> select CONCAT('(', c, ')'), CONCAT('(', vc, ')') from chars where vc = '2 '; +---------------------+----------------------+ | CONCAT('(', c, ')') | CONCAT('(', vc, ')') | +---------------------+----------------------+ | (2) | (2 ) | +---------------------+----------------------+ 1 row in set (0.00 sec)
存储引擎存储差异
由于比较常用的存储引擎innodb举例,innodb支持多种行格式,每种行格式对这两种字符的存储形式都有细微差异,具体一一讲述。
REDUNDANT(冗余)
CHAR(M)会分配M个字符的空间,如果字符集大小不固定,会按照字符集占用的最大字节数计算需要的存储空间,如utf8占用的存储空间是1-3 bytes,CHAR(8)占用的空间就是24 bytes,超出实际存储数据意外的空间会填充空格,如CHAR(10)的空间里面只存储5个字符,那么剩余空间会填充空格字符。
VARCHAR(M)会分配实际存储的数据的空间,如果 VARCHAR(10)实际存储了5个字符,那么会分配5个字符的空间,但如果实际数据后面有空格,不会被移除。
COMPACT(紧凑)
对于定长字符集,如ascii(1bytes),CHAR(M)会存储在一段固定的空间里面,空间内长度为 M * 字符集单字符长度
对于可变字符集,如utf8mb3(1-4bytes) and utf8mb4(1-4bytes),CHAR(M)会自少分配M bytes用来存储数据。但是如果存储的数据超过了M bytes,那么数据会在裁剪掉数据尾部空格后,按照数据大小分配空间,然后将数据存储在对应空间中。
VARCHAR(M)实际数据占用的存储空间同REDUNDANT(冗余)格式
DYNAMIC(动态)
存储模式同COMPACT(紧凑)模式(数据在溢出时处理方式不同,不再该文档讨论范围内)
COMPRESSED(压缩)
存储模式同COMPACT(紧凑)模式(数据在溢出时处理方式不同,对溢出数据有压缩,不再该文档讨论范围内)
其他MYSQL String类型比较
TEXT 和 BLOD
相同点
- 非严格SQL模式下存储数据时,超过最大长度,都会发出警告,在严格SQL模式下,会报错。
- TEXT/BLOD可能包含很多数据,因此当TEXT/BOLB列在结果集中时,会在临时表中处理而不是在内存中,因此如果确定不需要TEXT和BLOD应该尽量不使用select * from
不同点
- TEXT截断结尾空格在任何模式下都会产生warning,BLOD是二进制,没有空格的概念
- TEXT/BLOD在插入时都不会填充任何数据,在select的时候不会剥离任何数据
- TEXT上建立索引时,如两条记录A 和 'A ',索引比较时会忽略尾随空格,A 和 'A '值是相等的,BLOD值是不同的
到此这篇关于MySQL CHAR和VARCHAR区别的文章就介绍到这了,更多相关MySQL CHAR VARCHAR内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!