索引列顺序直接影响 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就找不到入口。
范围查询后列无法用于索引过滤
一旦某列出现范围操作(
>、
、<code>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 数值。
