##=====================================================================================##

MySQL支持的字符类型:

类型 大小 用途
CHAR 0-255字节 定长字符串
VARCHAR 0-65535 字节 变长字符串
TINYBLOB 0-255字节 不超过 255 个字符的二进制字符串
TINYTEXT 0-255字节 短文本字符串
BLOB 0-65 535字节 二进制形式的长文本数据
TEXT 0-65 535字节 长文本数据
MEDIUMBLOB 0-16 777 215字节 二进制形式的中等长度文本数据
MEDIUMTEXT 0-16 777 215字节 中等长度文本数据
LONGBLOB 0-4 294 967 295字节 二进制形式的极大文本数据
LONGTEXT 0-4 294 967 295字节 极大文本数据

 ##=====================================================================================##

CHAR(N)和VARCHAR(N)中N的问题

在MySQL 4.1版本前,CHAR(N)和VARCHAR(N)中的N指的是字节长度。
从MYSQL 4.1版本后,CHAR(N)和VARCHAR(N)中的N指的是字符的长度。

 ##=====================================================================================##

字节长度和字符长度

使用length(str)来查看str占用的字节数
使用char_length(str)表示str占用的字符数

对于多字节的字符编码来说,不同字符的编码长度不一样,如对于UTF来说,‘a’需要一个字节来存放,而对于中文‘你’则需要3字节来存放,
因此对于使用UTF8来存放的CHAR(N) 来说,最低使用N字节点空间,最高使用3N字节的空间,因此存储引擎在内部将CHAR类型视为变长字符类型来处理。

在MySQL中定义行的长度不能超过65535字节,因此会根据数据的字符集来限制VARCHAR(N)的N值,如当使用UTF8编码时,每个字符占用3个字节,一行的最大长度只能存放(65535-3)/3=21844个字符(在不考虑其他额外记录信息情况下),当创建表时指定的N超过最大值时,会将VARCHAR(N)类型装换为mediumtext类型。

DROP TABLE IF EXISTS tb1007;
DROP TABLE IF EXISTS tb1008;
CREATE TABLE `tb1007` (
  `id` INT (11) NOT NULL AUTO_INCREMENT,
  `c1` VARCHAR (21800) DEFAULT NULL,
  PRIMARY KEY (`id`)
);
CREATE TABLE `tb1008` (
  `id` INT (11) NOT NULL AUTO_INCREMENT,
  `c1` VARCHAR (21900) DEFAULT NULL,
  PRIMARY KEY (`id`)
);
SHOW CREATE TABLE tb1007; SHOW
CREATE TABLE tb1008; 输出: CREATE TABLE `tb1007` ( `id` int(11) NOT NULL AUTO_INCREMENT, `c1` varchar(21800) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 CREATE TABLE `tb1008` ( `id` int(11) NOT NULL AUTO_INCREMENT, `c1` mediumtext, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

 

PS1:对于VARCHAR类型,除包括字符数据需要的空间外,还额外需要1或2个字节来记录字符串的长度,对于字符串长度小于或等于255字节时使用1个字节表示,大于255字节的字符串的使用2字节表示。

PS2:当MySQL表使用ROW_FORMAT=FIXED时,对于定义VARCHAR类型的列会使用定长存储。

 ##=====================================================================================##

VARCHAR类型字符串空格问题
在MySQL 4.1及其之前版本,MySQL会截取字符串尾部的空格,
在MySQL 5.0及之后版本中,MySQL会保留字符串结尾的空格。

尾部空格是否截断是在MySQL Server层进行处理,与存储引擎层无关。
在MySQL 5.6版本测试如下:

create table tb002(c1 varchar(200));
insert into tb002(c1)values('   abc   ');
select concat('123',c1,'456') from tb002;
+------------------------+
| concat('123',c1,'456') |
+------------------------+
| 123   abc   456        |
+------------------------+

##=====================================================================================##

CHAR类型字符串空格问题
无论在MySQL 4.1版本之前还是之后,对于CHAR类型字符串,在检索时总会删除所有的末尾空格。
在MySQL 5.6版本测试如下:

drop table tb002;
create table tb002(c1 char(10));
insert into tb002(c1)values('   abc   ');
select concat('123',c1,'456') from tb002;
+------------------------+
| concat('123',c1,'456') |
+------------------------+
| 123   abc456           |
+------------------------+

##=====================================================================================##
VARCHAR和CHAR效率问题
1、当存储的所有数据都接近同一最大长度时,使用CHAR存放效率更高
2、当存储的数据长度差距较大,尤其少量数据长度较大时,使用CHAR存放会浪费较多的存储空间,使用VARCHAR存放更为合理
3、无论使用VARCHAR还是使用CHAR,都应遵守最小存储空间原则,避免将N设置过大造成性能问题。

##=====================================================================================##
其他字符问题
1、对于BINARY和VARBINARY类型,在存储时使用字节码来存放,在比较时依次按照每一个字节来对比
2、BINARY类型采用\0(零字节)而不是空格来进行填充
3、数据如何存储取决于存储引擎,Memory存储引擎只支持定长列,且Memroy存储引擎不支持BLOB和TEXT类型。
4、字符串填充和截取空格的行为在MySQL服务器层进行处理,因此对于所有存储引擎都一样

##=====================================================================================##
限制VARCHAR(N)中N值大小的意义:

对于不同存储引擎,在存放VARCHAR(N)类型数据时采用不同的存储方式,对于Innodb存储引擎,使用额外来1-2byte空间来存放变长列的数据长度,因此数据使用的存储空间与N值无明显关系,N值过大也不会导致数据占用过多的磁盘空间。
当数据从存储引擎读取到MySQL内存中时,数据在存储引擎中存放方式和在内存中的存放方式不同,存储引擎负责将数据进行转换放入至MySQL内存,而MySQL通常会分配固定大小的内存块来存放数据,因此对于VARCHAR(N)类型数据,当N值越大时,可能会导致MySQL分配越多的内存来存放数据,尤其在使用内存临时表进行排序或操作时,N值过大可能会导致内存临时表超过参数tmp_table_size阀值而升级为磁盘临时表,引发严重的性能问题。

PS1:由于测试过程中无法使用profile工具查看语句使用的内存信息,对于两个数据相同但VARCHAR(N)列N值差异较大的两个表做相同SQL查询发现性能没有太大差异,生成的临时表消耗的IO也接近,无法明确验证上述观点。

版权声明:本文为TeyGao原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/TeyGao/p/9113736.html