MySQL 8.0放宽单表索引上限至1024个,但不意味可随意创建:每增一个单列索引,DML操作就得额外执行一次B+树维护,5个索引时INSERT耗时达1个时的2.8倍,8个时翻4.5倍;高频更新字段、大字段前缀索引、JSON生成列索引、低基数字段索引及冗余前导列索引危害最大。

MySQL 8.0 确实放宽了单表索引数量的硬性限制(从 64 个提升到 1024 个),但这只是“能建”,不等于“该建”或“值得建”。
索引的物理代价没变:每次 INSERT、UPDATE、DELETE 仍要同步更新所有相关索引,buffer pool 仍会被低效索引挤占,优化器仍可能因索引过多而选错执行计划。
为什么放宽限制后反而更容易踩坑?
开发者误以为“上限高 = 安全阈值高”,结果在已有 5 个有效索引的表上又加了 3 个单列索引,实际造成:
• UPDATE 耗时翻倍(尤其更新带索引的字段)
• SHOW INDEX FROM t 显示大量 Cardinality 接近 0 的索引
• 慢查询日志里出现 Using filesort 频次不降反升——因为优化器被冗余索引干扰,放弃了本可用的复合索引
MySQL 8.0 新特性没解决的老问题
比如 sys.schema_unused_indexes 视图能查出长期未用的索引,但它不会告诉你:
• 这个索引是否和另一个索引功能重复(如已有 INDEX(a, b),又建了 INDEX(a))
• 这个索引是否只被某条低频后台任务用过一次,但拖慢了主业务写入
• DESC 索引只对 ORDER BY a DESC, b DESC 有效,换成 ORDER BY a ASC, b DESC 就失效,却仍占用空间和维护成本
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
怎么判断当前索引是不是“假宽松”下的真冗余?
直接看三件事:
• 执行 SELECT table_name, index_name, rows_read FROM performance_schema.table_io_waits_summary_by_index_usage WHERE count_star > 0 AND table_schema = 'your_db',rows_read = 0 的索引基本没被用过
• 对比 information_schema.STATISTICS 中各索引的 cardinality 和表总行数,比值低于 0.05 的单列索引大概率低效
• 检查是否有索引前缀重叠:比如 INDEX(a, b, c) 和 INDEX(a, b) 共存,后者就是冗余
INDEX(status),可能比加十个新索引更能缓解写入瓶颈。

















