mysql如何避免创建冗余索引_mysql索引设计建议

5次阅读

冗余索引指一个索引的最左前缀被另一索引完全覆盖,丧失独立查询价值;如已有index(a,b,c),则index(a,b)冗余,而index(b,a)不冗余。

mysql如何避免创建冗余索引_mysql索引设计建议

怎么判断两个索引是否冗余

mysql 中的冗余索引,是指一个索引的列前缀已经完全被另一个索引覆盖,导致它无法提供额外的查询能力。比如已有 INDEX (a, b, c),再建 INDEX (a, b) 就是冗余的——因为前者能完全替代后者的所有使用场景。

关键看「最左前缀匹配」是否被覆盖:只要已有索引的前 N 列和新索引完全一致(且顺序相同),新索引就大概率冗余。

  • INDEX (user_id, created_at)INDEX (user_id) → 后者冗余
  • INDEX (status, updated_at)INDEX (status, updated_at, id) → 前者冗余
  • INDEX (a, b)INDEX (b, a) → 不冗余(顺序不同,适用场景不同)
  • INDEX (a)INDEX (a, b) WHERE b > 0 → 不冗余(后者是条件索引,覆盖场景不同)

如何用 SQL 找出潜在冗余索引

MySQL 5.7+ 可通过 sys.schema_redundant_indexes 视图快速定位。先确认该视图已启用(默认开启):

SELECT * FROM sys.schema_redundant_indexes;

结果中会列出 object_schemaobject_name(表名)、redundant_index_namedominant_index_name,后者是“压倒性”更强的那个索引。

注意:sys 库依赖 performance_schema,若关闭了相关采集项(如 events_statements_history_long),可能影响部分统计,但冗余判断本身不依赖运行时数据,一般可靠。

哪些索引组合特别容易踩坑

实际建表或优化时,这几类组合高频出现冗余,且常被忽略:

  • 主键是 int 自增,又单独为该字段建 INDEX (id) → 完全多余(主键本身就是聚簇索引,且可被用于单列查找)
  • 联合索引包含主键列,例如 INDEX (tenant_id, id),而 id 是主键 → 若查询只用 id,仍走不了这个索引;但若已有 PRIMARY KEY (id),那 (tenant_id, id) 并不冗余,只是要注意它对 tenant_id 单查有效,对 id 单查无效
  • 全文索引和普通索引混用:FULLTEXT (title, content)INDEX (title) → 后者在全文检索场景下无意义,但若还有 WHERE title = ? 查询,则不能删,得看实际 SQL
  • 唯一索引 + 普通索引重复列:UNIQUE (email)INDEX (email) → 后者绝对冗余(唯一索引自带 B+ 树结构,查询性能一致)

删索引前必须验证的三件事

即使确认冗余,也不能直接 DROP INDEX。生产环境必须核对:

  • 是否有慢查询正依赖该索引?查 performance_schema.events_statements_summary_by_digest 或慢日志里 using index 的提示
  • 是否被外键约束隐式使用?SHOW CREATE table tblFOREIGN KEY 定义,MySQL 要求外键列必须有索引,且不能仅靠前缀索引覆盖(如 INDEX (col(10)) 不行)
  • 是否在某个 ORDER BY + LIMIT 场景中起到避免 filesort 的作用?例如 WHERE a = ? ORDER BY b LIMIT 10 依赖 INDEX (a, b),而你只留了 INDEX (a, b, c) —— 这没问题;但如果删掉的是 INDEX (a, b),只留 INDEX (b, a),那就失效了

冗余的本质不是“长得像”,而是“能力被白嫖”。哪怕列数、顺序、类型都对得上,也得拉出真实查询计划(EXPLAIN format=TREE)看 optimizer 实际选了谁。这点最容易被跳过。

text=ZqhQzanResources