MySQL 基础--字符类型
##=====================================================================================##
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也接近,无法明确验证上述观点。