mysql索引顺序对查询性能有影响吗_mysql索引设计注意事项

2次阅读

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

mysql索引顺序对查询性能有影响吗_mysql索引设计注意事项

索引列顺序直接影响 WHERE 条件能否命中索引

mysql 使用 B+ 树索引,数据按索引定义的列顺序物理排序。如果查询条件没用上最左前缀,后续列就无法利用索引下推或范围扫描。比如有复合索引 INDEX (a, b, c)

  • WHERE a = 1 AND b = 2 → 可用全部两列做等值查找
  • WHERE a = 1 AND c = 3 → 仅能使用 ac 被跳过(b 缺失导致断层)
  • WHERE b = 2 AND c = 3 → 完全无法使用该索引

本质是 B+ 树层级结构决定的:第一层按 a 排序,第二层才在每个 a 值内按 b 排序,没有 a 就找不到入口。

范围查询后列无法用于索引过滤

一旦某列出现范围操作(>BETWEENLIKE 前缀通配除外),其右侧所有列都只能用于回表,不能参与索引查找或 WHERE 下推。

  • INDEX (a, b, c),查询 WHERE a = 1 AND b > 2 AND c = 3c = 3 不会走索引过滤,只靠回表后判断
  • 若把顺序改成 INDEX (a, c, b),同样无法让 cb > 2 后生效

所以要把高选择性且常用于等值查询的列放左边,范围列尽量靠右;避免把 created_at > '2024-01-01' 这类放在中间位置。

ORDER BYGROUP 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 数值。

text=ZqhQzanResources