MySQL联合索引需按等值条件→范围条件顺序设计,覆盖索引要求SELECT字段在索引后缀位置,ORDER BY/GROUP BY须与索引列顺序及方向严格一致,优先用联合索引替代单列索引并定期清理冗余索引。

WHERE 条件字段顺序决定索引列顺序
MySQL 的 B+ 树索引是按定义顺序逐列匹配的,WHERE a = ? AND b = ? AND c > ? 这类查询,最有效的索引通常是 INDEX(a, b, c),而不是反过来。一旦某列用了范围查询(如 >、BETWEEN、LIKE 'abc%'),其右侧所有列就无法用于索引查找(只能用于过滤)。
实操建议:
- 把等值条件(
=、IN)字段放在索引左侧,且高频、高区分度的优先 - 范围条件字段放中间或靠右,避免它左边有低效列(比如
INDEX(status, create_time)中status若只有 2–3 个值,会严重降低索引选择性 - 用
EXPLAIN看key_len:如果远小于索引总长度,说明没用全
SELECT 列是否要包含在索引里?看是否能覆盖查询
当 SELECT 的所有字段都来自索引本身(包括 WHERE 和 SELECT 字段),MySQL 就不必回表查聚簇索引,这种叫「覆盖索引」。例如 SELECT id, name FROM users WHERE city = 'Beijing',建 INDEX(city, id, name) 就能让查询完全走索引。
但注意:
- 不是所有字段都适合加进索引——过宽的索引会拖慢写入、占用更多 Buffer Pool
-
TEXT/BLOB类型不能直接加入索引;VARCHAR(500)建索引要加前缀(如name(100)),否则可能超出限制 - 联合索引中,
SELECT字段必须出现在索引定义的**后缀位置**才有效;INDEX(a, b)能覆盖SELECT a或SELECT a,b,但不能覆盖SELECT b
ORDER BY 和 GROUP BY 很容易被索引忽略
即使 WHERE 条件命中了索引,如果 ORDER BY 字段不在该索引中,或者顺序/方向不一致(如索引是 (a ASC, b ASC),而查询写 ORDER BY a DESC, b ASC),MySQL 仍会触发 filesort。
常见陷阱:
-
ORDER BY多字段时,必须和索引列顺序、升降序严格一致(8.0+ 支持混合排序,但需显式声明,如INDEX(a ASC, b DESC)) -
GROUP BY在绝大多数情况下等价于ORDER BY,同样依赖索引顺序;如果不需要结果排序,可加ORDER BY NULL显式禁用排序 - 含
LIMIT的分页查询(如ORDER BY created_at LIMIT 10000, 20)即使有索引,也会扫描前 10020 行——这时更适合用游标分页(WHERE created_at < ? ORDER BY created_at DESC LIMIT 20)
别盲目给每个 WHERE 字段单独建索引
单列索引在多条件查询中往往无效。比如有 INDEX(a) 和 INDEX(b),查询 WHERE a = 1 AND b = 2 通常只会用上其中一个(优化器选它认为更优的那个),另一个被丢弃。
真正该做的:
- 优先合并为联合索引,按实际查询模式组合(如高频查
a + b,就建INDEX(a, b);若还常查a + b + c,可扩展为INDEX(a, b, c)) - 用
SHOW INDEX FROM table检查重复冗余索引,比如已有INDEX(a, b),再建INDEX(a)就是浪费 - 监控
information_schema.STATISTICS或使用sys.schema_unused_indexes(需启用 performance_schema)识别长期未被使用的索引
索引不是越多越好,每多一个,INSERT/UPDATE/DELETE 都要多维护一棵 B+ 树,而且优化器在复杂查询中可能因索引过多反而选错执行计划。










