作者:刘晨,网名 bisal ,具有十年以上的应用运维工作经验,目前主要从事数据库应用研发能力提升和技术管理相关的工作,Oracle ACE(Alumni),腾讯云TVP,拥有 Oracle OCM & OCP 、EXIN DevOps Master 、SCJP 等国际认证,国内首批 Oracle YEP 成员,OCMU 成员,《DevOps 最佳实践》中文译者之一,CSDN & ITPub 专家博主,公众号”bisal的个人杂货铺”,长期坚持分享技术文章,多次在线上和线下分享技术主题。
爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
本文约 800 字,预计阅读需要 3 分钟。
1背景
同事反馈说某个 MySQL 数据库创建索引提示错误,模拟报错如下:
CREATE INDEX t_reg_code_idx USING BTREE ON t(reg_code)
BLOB/TEXT column 'reg_code' used in key specification without a key length
从该提示可知,给 T 表的 reg_code
列创建一个 BTREE 索引,而这个 reg_code
列的字段类型是 BLOB 或 TEXT。
需要在键的说明中有长度定义,这是什么意思?
2表索引前缀长度限制
MySQL 8.0
从 MySQL 8.0 的官方手册可以找到这段对 Index Prefixes[1] 的说明。意思是如果对 BLOB 或者 TEXT 列创建索引,必须指定索引的前缀长度。对于使用 REDUNDANT 或者 COMPACT 行格式的 InnoDB 表,索引前缀最多 767 个字节,对于使用 DYNAMIC 或者 COMPRESSED 行格式的 InnoDB 表,索引前缀的上限最多是 3072 个字节,如果是 MyISAM 表,前缀长度最多可以达到 1000 个字节。

MySQL 5.7
而 MySQL 5.7 官方手册中,对索引前缀的限制有所不同,InnoDB 表的索引前缀最多可以达到 1000 个字节(此处我认为是错误的,应该是 3072),但前提是设置了 innodb_large_prefix(只对 DYNAMIC 或者 COMPRESSED 行格式生效,对 REDUNDANT 或者 COMPACT 行格式无效),否则只能达到 767 个字节。

因此可知,MySQL 8.0 在 InnoDB 表的索引前缀长度限制的设置上有所调整,但是限制还是有,这是和 Oracle 等数据库有所不同的一个特性。
3验证
通过实验,验证 MySQL 8.0 对于前缀长度的限制。
创建一张 row format 是 COMPACT 的 InnoDB 表,指定前缀长度 10000,提示最大键的长度只能是 767 个字节。
create table test01 (
id int(30) not null auto_increment,
t_a text,
primary key(id),
index idx_t_a(t_a(10000))
) COLLATE='gbk_chinese_ci' ENGINE=InnoDB ROW_FORMAT=COMPACT;
SQL 错误 [1071] [42000]: Specified key was too long; max key length is 767 bytes
创建一张 row format 是 COMPRESSED 的 InnoDB 表,指定前缀长度 10000,提示最大键的长度只能是 3072 个字节。
create table test01 (
id int(30) not null auto_increment,
t_a text,
primary key(id),
index idx_t_a(t_a(10000))
) COLLATE='gbk_chinese_ci' ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
SQL 错误 [1071] [42000]: Specified key was too long; max key length is 3072 bytes
4总结
抛开技术问题,和同事追问了下这个操作的背景。原始需求是某个厂商的 ETL 任务需要从源库将数据导入目标库,源库字段是 VARCHAR 类型,目标库定义为 TEXT,才间接引起的这个问题。推测一种可能的原因,因为 VARCHAR、TEXT 都可以存储字符串类型的数据,所以没做区分,另一种可能,为了图省事儿,不用关注源库和目标库字符串类型定义的长度,直接设置了 TEXT 类型,保证肯定能存下。
无论是何种原因,TEXT 这种大字段类型,一般不推荐作为索引检索字段,因为往往它存储了很多字符,索引存储空间会占用更多,索引的区分度也会有影响。
因此,虽然这个问题表象是个技术问题,但实际上来源于不合理的设计,我们在进行应用设计、数据库设计时,如果能多考虑一些合理性,避免一些所谓的省事儿,可能在实际使用过程中,就会更顺畅,相辅相成的。
参考资料
column indexes: https://dev.mysql.com/doc/refman/8.0/en/column-indexes.html
本文关键字:#MySQL 8.0# #字段类型# #索引#
阅读推荐
技术分享 | 如何避免 RC 隔离级别下的 INSERT 死锁
技术分享 | Windows 下 MySQL 源码学习环境搭建步骤【建议收藏】
技术译文 | MySQL 和 MariaDB 版本管理的历史背景及差异
3306π 数据库朋友圈 北京站
【3306π 数据库朋友圈】北京站 Meetup 将于 9 月 16 日(周六)举办。
活动邀请了数据库行业的众多资深专家出席,议程包含各位专家技术演讲,问题讨论提问和《2023 年数据库发展现状总结》等环节。
爱可生研发经理 - 阎虎青先生将出席本次活动,带来《TensorDB - 用 GPU 检索的向量数据库》主题演讲,尽请期待~
🙋 提前提问地址:

2023 OSCAR 开源产业大会开源集市
本次大会首次设置了 OSCAR 开源集市,爱可生开源社区受到邀请,将在开源集市设置展位与互动活动,成功完成即可获得社区专属礼品~
会议名称:2023 OSCAR 开源产业大会 会议时间:2023 年 9 月 21 日 会议地点:北京市海淀区丽亭华苑酒店

爱可生技术会议 上海站

关于 SQLE
爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。
SQLE 获取
🔗 Github https://github.com/actiontech/sqle
📚 文档 https://actiontech.github.io/sqle-docs/
💻 官网 https://opensource.actionsky.com/sqle/
👥 微信技术交流群:添加管理员微信 ActionOpenSource




