索引列顺序必须遵循最左前缀原则:WHERE条件未用最左列则后续列失效;范围查询后列无法索引过滤;ORDER BY/GROUP BY需完全匹配最左连续列且方向一致;应按查询模式优先级而非单纯区分度排布。

索引列顺序直接影响 WHERE 条件能否命中索引
MySQL 使用 B+ 树索引,数据按索引定义的列顺序物理排序。如果查询条件没用上最左前缀,后续列就无法利用索引下推或范围扫描。比如有复合索引 INDEX (a, b, c):
-
WHERE a = 1 AND b = 2→ 可用全部两列做等值查找 -
WHERE a = 1 AND c = 3→ 仅能使用a,c被跳过(b缺失导致断层) -
WHERE b = 2 AND c = 3→ 完全无法使用该索引
本质是 B+ 树层级结构决定的:第一层按 a 排序,第二层才在每个 a 值内按 b 排序,没有 a 就找不到入口。
范围查询后列无法用于索引过滤
一旦某列出现范围操作(>、、BETWEEN、LIKE 前缀通配除外),其右侧所有列都只能用于回表,不能参与索引查找或 WHERE 下推。
-
INDEX (a, b, c),查询WHERE a = 1 AND b > 2 AND c = 3→c = 3不会走索引过滤,只靠回表后判断 - 若把顺序改成
INDEX (a, c, b),同样无法让c在b > 2后生效
所以要把高选择性且常用于等值查询的列放左边,范围列尽量靠右;避免把 created_at > '2024-01-01' 这类放在中间位置。
ORDER BY 和 GROUP BY 必须匹配索引最左前缀才能避免 filesort
MySQL 仅当 ORDER BY 列完全对应索引最左连续列,且排序方向一致(全 ASC 或全 DESC),才能直接利用索引有序性。例如:
INDEX (user_id, status, created_at)-
SELECT * FROM t WHERE user_id = 123 ORDER BY status, created_at→ 无 filesort -
SELECT * FROM t WHERE user_id = 123 ORDER BY created_at→ 仍需 filesort(跳过了status) -
SELECT * FROM t WHERE user_id = 123 ORDER BY status DESC, created_at ASC→ filesort(混合方向)
注意:8.0+ 支持降序索引,但老版本遇到混合排序基本只能靠覆盖索引或调整查询逻辑绕开。
区分度高的列优先,但别忽略查询模式本身
高区分度(如 user_id)通常适合放左边,但实际要结合 WHERE 组合频次看:
- 如果 90% 查询都是
WHERE tenant_id = ? AND status = ?,哪怕tenant_id区分度低,也应放最左(因为必须用它过滤租户隔离) - 有
WHERE a IN (?, ?, ?) AND b = ?,a是多值等值,b是单值等值,优先把b放左更利于精确查找(IN 在某些场景下可走 range) - 避免把
is_deleted TINYINT放最左——即使加了索引,优化器大概率因选择率太低而拒用
真正关键的是「哪些列总是一起出现、是否常被用于等值、有没有范围、是否承担排序/分组」——不是单纯看 cardinality 数值。











