今天看了实习生的建表语句,里面有很多字段都是varchar(255),觉得很奇怪便提了一句了,
实习生:“因为mysql 有规范,当varchar中的值大于255时候mysql会多加一个1个字节用户存储长度,小于255时候就只需要要1个字节存储长度”
然后看了一下字段和表的发现字符集是utf8mb4.猜想他应该知识没有学透,所以给他讲解了一下同时最一下整理记录
字符&字节
mysql varchar中设置的是字符,mysql 文件存储的是字节,所以从字符到字节会涉及到一个转换。
而mysql的规定是:“可变长度类型,varchar(n)则表示可存储char_length(n)长度的字符,储存空间占用(字符集最大占用 × n + 1 or 2长度字节),字节数 > 255 时用2字节表示长度。” 因为1byte = 8bit => 2^8 -1 = 255
mysql各字符集
latin1: 1character=1byte,
gbk: 1character=2bytes,
utf8: 1character=3bytes,
utf8mb4: 1character=4bytes,
Mysql 为什么经常设置 varchar 长度为 255
是因为索引长度的问题,而不是多了一个1字节存储
Mysql 单列索引长度为 767,所以在 utf8 编码下,一个字符为 3bytes,那么 255乘以3=765,由于字节长度超过255会再加2个字节存储长度, 所以在utf8的编码下varchar(255)的列长刚好是767;刚好为能够建立索引长度的最大值;如果超出了这个值,那么 mysql 会自动将这一列的索引变为前缀索引(同时截取前255个字符)
同理在 utf8mb4 编码下,一个字符为 4bytes,那么 255乘以4=1020,则超出了767这个值,那么 mysql 会自动将这一列的索引变为前缀索引(同时截取前255个字符)
行大小限制
在mysql中,mysql有65535字节的最大行大小限制。也就是说,所有字段占用的空间都被包含在65535字节中
下面做一个测试,建立一张表包含2个字段,每个字段都是varchar(8191)
总字节长度 = (8191 乘以4 + 2)乘以2 = 65532 是可存储的最大长度
下面修改一个字段长度为8192
为什么联合索引长度是 3072
InnoDB 一个 page 的默认大小是 16k。由于是 Btree 组织,要求叶子节点上一个 page 至少要包含两条记录(否则就退化链表了)。
所以一个记录最多不能超过 8k。又由于 InnoDB 的聚簇索引结构,一个二级索引要包含主键索引,因此每个单个索引不能超过 4k 。
由于需要预留和辅助空间,扣掉后不能超过 3500字节;所以在utf8编码下 1024*3=3072。
在MySQL5.5版本,引入了innodb_large_prefix,用来禁用大型前缀索引,以便与不支持大索引键前缀的早期版本的InnoDB兼容
开启innodb_large_prefix可以使单索引的长度限制达到3072字节(但是联合索引总长度限制还是3072字节),禁用时单索引的长度限制为767字节