当MySQL版本不一致,尤其是发生较大的版本变动时,总是容易引发一些灾难。今天我们就来谈一谈不同版本下 MySQL 索引引发的问题。


create table if not exists `todo_msg` (
`id` varchar(32) not null COMMENT '主键ID',
`code` varchar(20) default null COMMENT '任务编码',
`name` varchar(255) default null COMMENT '任务名称',
primary key (`id`),
key `idx` (`name`)
) ENGINE = InnoDB default CHARSET = utf8mb4 COMMENT = '待办信息表';


FBI WARNING - Specified key was too long; max key length is 767 bytes


原因: 索引长度超出限制,最大的允许的字节长度为 767 字节。

MySQL的InnoDB存储引擎存在索引长度限制,该限制与参数 innodb_large_prefix 相关。

系统变量innodb_large_prefix开启了,则对于使用DYNAMIC或COMPRESSED行格式的InnoDB表,索引键前缀限制为3072字节。

如果禁用innodb_large_prefix,不管是什么表,索引键前缀限制为767字节。

可以通过 show variables; 命令系统的环境变量。

MySQL 5.6 版本引入 innodb_large_prefix, 该版本 innodb_large_prefix 默认值是关闭的。

MySQL 5.7 版本, innodb_large_prefix 默认值是 ON。

MySQL 8.X 版本,移除了 innodb_large_prefix 值。 当ROW_FORMAT为 DYNAMIC 或 COMPRESSED 时,索引前缀限制为3072字节。 当当ROW_FORMAT为 REDUNDANT 或 COMPACT 时, 索引前缀长度为 767字节。

MySQL 从5.7.9 版本后,ROW_FORMAT 默认为 DYNAMIC。

ROW_FORMAT

innodb_default_row_format

通过下述命令查看 MySQL 环境变量 show variables;

在不同的编码中,一个字符所占的字节长度不同。 gbk,一个汉字占2个字节

utf8,一个汉字占3个字节

utf8mb4, 一个汉字占4个字节

utf8mb4的索引长度为 767/4 = 191, utf8的索引长度为 767/3 = 255

解决方案

创建表结构时,指定索引的最大长度范围

create table if not exists `baas_notice_record` (
`id` varchar(32) not null,
`title` varchar(200) not null,
`content` varchar(5000) not null,
`notice_type` varchar(20) not null,
`send_type` int(1) default '0',
`receivers` varchar(300) not null,
`note_status` int(1) default '0',
`send_time` datetime default null,
`create_date_time` datetime not null,
`ytenant_id` varchar(36) not null,
`dr` int(1) default '0',
`ts` varchar(32) not null,
`tenant_id` varchar(36) not null,
primary key (`id`),
key `idx_title` (`title`(190))
) ENGINE = InnoDB;