MySQL DataType--字符串类型
VARCHAR类型存储空间问题
当MySQL表使用ROW_FORMAT=FIXED时,对于定义VARCHAR类型的列会使用定长存储。 对于VARCHAR类型,除包括字符数据需要的空间外,还额外需要1或2个字节来记录字符串的长度,对于字符串长度小于或等于255字节时使用1个字节表示,大于255字节的字符串的使用2字节表示。对于多字节的字符编码来说,不同字符的编码长度不一样,如对于UTF来说,‘a’需要一个字节来存放,而对于中文‘你’则需要3字节来存放, 因此对于使用UTF8来存放的CHAR(N) 来说,最低使用N字节点空间,最高使用3N字节的空间,因此存储引擎在内部将CHAR类型视为变长字符类型来处理。 使用length(str)来查看str占用的字节数 使用char_length(str)表示str占用的字符数 在MySQL 4.1版本前,CHAR(N)和VARCHAR(N)中的N指的是字节长度。 从MYSQL 4.1版本后,CHAR(N)和VARCHAR(N)中的N指的是字符的长度。 对于VARCHAR(N)字段的结尾空格处理: 在MySQL 4.1及其之前版本,MySQL会截取字符串尾部的空格, 在MySQL 5.0及之后版本中,MySQL会保留字符串结尾的空格。 如在MySQL 5.6版本中,使用默认字符集utf8的varchar(5)类,最多可以存放5个数字或5个汉字。
VARCHAR类型字符串空格问题
在MySQL 4.1或更老版本中,MySQL会剔除VARCHAR列末尾的空格,而在MySQL 5.0或更高版本中,MySQL在存储和检索时会保留末尾空格。 尾部空格是否截断是在MySQL Server层进行处理,与存储引擎层无关。
CHAR类型的空格问题
无论在MySQL 4.1版本之前还是之后,对于CHAR类型字符串 1、在存储时,先补足空格再存储,无论用户数据中是否包含空格。 2、在读取时,总是删除数据尾部的空格,即使用户数据在写入时包含空格。
存储引擎对字符类型的影响
数据如何存储取决于存储引擎,Memory存储引擎只支持定长列,且Memroy存储引擎不支持BLOB和TEXT类型。 字符串填充和截取空格的行为在MySQL服务器层进行处理,因此对于所有存储引擎都一样。 对于BINARY和VARBINARY类型,在存储时使用字节码来存放,在比较时依次按照每一个字节来对比。 BINARY类型采用\0(零字节)而不是空格来进行填充。 在处理VARCHAR类型数据时,MySQL通常会分配固定大小的内存块来保存内部值,因此对于相同字符串,更长的列会消耗更多的内存,使得在使用内存临时表或磁盘临时表进行排序或操作时消耗更多的资源并且性能低下。 当使用UTF8编码时,每个字符占用3个字节,而MySQL定义行的长度不能超过65535,而且每行还需要至少额外的字节记录该行的信息,因此在UTF8编码下,VARCHAR(N)中的N值最大为(65535-3)/3=21844,当创建表时N超过该最大值,则会将VARCHAR(N)转换成mediumtext类型。
限制VARCHAR(N)中N值大小的意义:
对于不同存储引擎,在存放VARCHAR(N)类型数据时采用不同的存储方式,对于Innodb存储引擎,使用额外来1-2byte空间来存放变长列的数据长度,因此数据使用的存储空间与N值无明显关系,N值过大也不会导致数据占用过多的磁盘空间。 当数据从存储引擎读取到MySQL内存中时,数据在存储引擎中存放方式和在内存中的存放方式不同,存储引擎负责将数据进行转换放入至MySQL内存,而MySQL通常会分配固定大小的内存块来存放数据,因此对于VARCHAR(N)类型数据,当N值越大时,可能会导致MySQL分配越多的内存来存放数据,尤其在使用内存临时表进行排序或操作时,N值过大可能会导致内存临时表超过参数tmp_table_size阀值而升级为磁盘临时表,引发严重的性能问题。 对于含有1千万数据的表,假设表中有使用UTF8字符集的VARCHAR(1000)列,每个字符占用3字节,如果查询扫描整表进行排序,那么1000000*1000*3字节,就会生成约为30GB的磁盘临时表。
修改字符集注意事项
# 将表的默认字符集修改为UTF8MB4 ALTER TABLE table_name CHARSET=utf8mb4; ## 使用MODIFY方式 ALTER TABLE tb001 MODIFY C1 LONGTEXT CHARACTER SET utf8mb4; ## 使用CHANGE方式 ALTER TABLE tb001 CHANGE C1 C1 LONGTEXT CHARACTER SET utf8mb4; PS1: 修改表字符集后,并不会自动修改现有列的字符集,需要单独修改。