共计 1128 个字符,预计需要花费 3 分钟才能阅读完成。
1.varchar 类型
(1)varchar (N):中的 N 指的是字符的长度,即:该字段最多能存储多少个字符 (characters),不是字节数。不管是一个中英文字符或者数字、或者一个汉字,都当做一个字符。
【a, 我,1 都是一个字符,但是 a 和 1 是一个字节,‘我’(utf8 下)是 3 个字节。utf8mb4 下:汉字也是 3 个字节,表情符号是 4 个字节】
(2)varchar 最多能存储 65535 个字节的数据。
65535 = 所有字段的长度 + 变长字符的长度标识 + NULL 标识位
变长字符的长度标识:用 1 到 2 个字节表示实际长度(长度 >255 时, 需要 2 个字节;<255 时,需要 1 个字节)
NULL 标识位:varchar 字段定义中带有 default null 允许列空, 则需要 1 bit 来标识,每 8 个 bits 的标识组成一个字段。一张表中存在 N 个 varchar 字段,那么需要(N+7)/8(取整)bytes 存储所有的 NULL 标识位。
(3)虽然 InnoDB 内部支持 varchar 65535 字节的行大小,但是 MySQL 本身对所有列的合并大小施加了 65535 字节的行大小限制。详情见例子
2.varchar 长度的编编限制:
字符类型若为 gbk,每个字符最多占 2 个字节,最大长度不能超过 32766;
字符类型若为 utf8,每个字符最多占 3 个字节,最大长度不能超过 21845。
字符类型若为 utf8mb4,每个字符最多占 4 个字节,最大长度不能超过 16283。
若定义的时候超过上述限制,则 varchar 字段会被强行转为 text 类型,并产生 warning。
3. 例子
若一个表定义为
create table t4(c int, c2 char(30), c3 varchar(N)) charset=utf8;
则此处 N 的最大值为 (65535-1-2-4-30*3)/3=21812
减 1:实际行存储从第二个字节开始;
减 2:varchar 头部的 2 个字节表示长度
减 4:原因是 int 类型的 c 占 4 个字节;
减 30*3:原因是 char(30)占用 90 个字节,编码是 utf8。
如果被 varchar 超过上述的 b 规则,被强转成 text 类型,则每个字段占用定义长度为 11 字节,当然这已经不是“varchar”了。
mysql> alter table t4 modify column c3 varchar(21813);
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs