写点什么

MySQL 切换字符集引发的思考(一)

作者:石小天
  • 2023-08-17
    上海
  • 本文字数:1141 字

    阅读完需:约 4 分钟

背景

故事是从一个生产系统 SQL 变更开始的,我们需要将一张表的字符集从 utf8 变更为 utf8mb4,起初的想法是 utf8mb4 能存储更多类型如 emoji 表情类的数据,这个变更应该没什么大的影响。但仔细思考一番,再结合与团队成员讨论、网上查的资料,变更可能会带来如下影响

  1. 如果在 varchar 字段上有索引,utf8 可支持最大 255 长度,而 utf8mb4 只能支持到 191 长度,故 SQL 可能执行失败。还有另外一种说法是 SQL 执行不会失败,但最终创建成功的是前缀索引。

  2. 相同字符集做关联查询的性能优于不同字符集,故存在性能下降风险。

  3. 变更字符集会导致索引重建,故存在性能下降风险。

出于技术人的好奇,且网上资料质量良莠不齐,决定接下来对上述问题一一进行论证。

本次将对第一个问题做验证


论证过程

初步想法比较简单,只需要创建一张表,设置字段类型为 varchar 并创建索引,看是否失败,如果成功再 explain 一下看下索引键的长度即可

CREATE TABLE `t_test_idx` (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',  `comment` varchar(192) DEFAULT NULL COMMENT '用户评论',  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评论表'
create index idx_comment on t_test_idx (comment);
复制代码

执行成功,并没有报错

接下来插入一些数据,再 explain 一下

INSERT INTO `rjhy-digit-visual`.t_test_idx (comment) VALUES ('初步')INSERT INTO `rjhy-digit-visual`.t_test_idx (comment) VALUES ('初步想法')explain select * from t_test_idx where comment = '初步'
复制代码


这里可以看到用到了索引,key_len 是 771

这里简单介绍下 key_len 计算的规则,utf8mb4 编码下,varchar(n)占用的字节数为 4n+2,如果字段可以为空,则需要再增加一个字节。故 771=4*192+2+1,长度是对的上的,说明没有被截断为前缀索引。

初步结论:utf8mb4 字符集情况下,在长度超过 192 的 varchar 字段上,可以正常创建索引并使用。


故事到这里似乎可以结束了,然而 191,255 两个数字却还在我脑海里,既然可以正常使用,为什么网上会有这么多关于 191,255 的讨论?

进一步搜索资料,MySQL 5.6 版本引入了 innodb_large_prefix 参数,用于解决索引键长度限制的问题

该参数在 5.6 版本默认关闭,在 5.7 版本默认开启,而我测试使用的 MySQL 版本正是 5.7。

使用如下命令查看,开关确实处于开启状态。

SHOW VARIABLES LIKE 'innodb_large_prefix';
复制代码


鉴于测试使用 MySQL 为团队公用测试资源,不在上面修改全局参数做进一步验证,后续通过其他方式进行验证。

结论

在 MySQL 5.7 版本中,innodb_large_prefix 开启的状态下,utf8mb4 字符集的 varchar 字段即使长度超过 191 依然可以正常创建索引,不会转为前缀索引。

待验证

innodb_large_prefix 关闭状态下,utf8mb4 字符集的 varchar 字段长度超过 191 是否可创建索引,如果可以,是否会转为前缀索引。

用户头像

石小天

关注

还未添加个人签名 2018-11-07 加入

还未添加个人简介

评论

发布
暂无评论
MySQL切换字符集引发的思考(一)_MySQL_石小天_InfoQ写作社区