mysql联合索引如何使用_mysql查询优化实践

7次阅读

联合索引最左匹配指严格按定义顺序从左到右逐列匹配,遇范围查询或跳过某列则后续列失效;如索引(user_id,status,create_time),where user_id=123 and status=’active’可用前两列,而where status=’active’则完全不走索引。

mysql联合索引如何使用_mysql查询优化实践

联合索引的最左匹配到底匹配什么

mysql 的联合索引不是“只要用了其中某个字段就走索引”,而是严格按定义顺序从左到右逐列匹配,直到遇到范围查询(>>=、<code>BETWEENLIKE 前缀匹配除外)或跳过某列,后续列就失效了。

比如有联合索引 INDEX idx_user_status_time (user_id, status, create_time)

  • WHERE user_id = 123 AND status = 'active' → 走索引,用到前两列
  • WHERE user_id = 123 AND create_time > '2024-01-01' → 只用到 user_idcreate_time 无法跳过 status 直接生效
  • WHERE status = 'active' AND create_time > '2024-01-01' → 完全不走该联合索引(没出现最左列 user_id

哪些查询能用上 (user_id, status, create_time) 联合索引

关键看 WHERE 条件是否构成「连续的最左前缀」,且等值条件在范围条件之前。

  • WHERE user_id = 123
  • WHERE user_id = 123 AND status = 'active'
  • WHERE user_id = 123 AND status = 'active' AND create_time BETWEEN '2024-01-01' AND '2024-01-31'
  • WHERE user_id IN (123, 456) AND status = 'active'IN 算等值组,仍可继续匹配)
  • WHERE user_id > 100 AND status = 'active'user_id 是范围,status 不再生效)
  • WHERE status = 'active' ORDER BY create_time(无 user_id,索引无法定位扫描起点)

ORDER BY 和 GROUP BY 怎么借联合索引避免 filesort

如果 ORDER BY 字段顺序和联合索引最左连续部分完全一致(且都是同向,如全 ASC 或全 DESC),MySQL 可直接利用索引有序性,无需额外排序。

还是以 INDEX idx_user_status_time (user_id, status, create_time) 为例:

  • WHERE user_id = 123 ORDER BY status, create_time → 匹配索引前缀,免排序
  • WHERE user_id = 123 AND status = 'active' ORDER BY create_time → 精确到前两列后,第三列天然有序
  • WHERE user_id = 123 ORDER BY create_time → 跳过 status,索引中 create_time 并非全局有序
  • ⚠️ ORDER BY user_id DESC, status ASC → 混合方向,5.7+ 支持,但需确认执行计划中 Extra 是否含 using filesort

为什么加了联合索引,EXPLAIN 还显示 type=ALL

常见原因不是索引建错了,而是查询本身没触发最左匹配,或者优化器认为全表扫描更快(比如返回行数占比高、统计信息不准、存在隐式类型转换)。

排查步骤:

  • EXPLAIN format=TREE(8.0+)或 EXPLAIN ANALYZE 看真实执行路径
  • 检查 WHERE 中字段类型是否和索引列一致(如 user_idBIGINT,但传了字符串 '123',会触发隐式转换,索引失效)
  • 运行 ANALYZE table table_name 更新统计信息
  • 临时强制走索引测试:select ... FROM t USE INDEX (idx_user_status_time) WHERE ...
  • 注意:SELECT * + 联合索引覆盖不全时,可能回表代价高,优化器主动放弃索引

联合索引真正起效的前提,是你的查询条件和排序需求能被它「连续地、无跳跃地」覆盖。少一个等值条件,或多一个范围起点,后面列就成摆设——这点比单列索引容易误判得多。

text=ZqhQzanResources