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

联合索引的最左匹配到底匹配什么
MySQL 的联合索引不是“只要用了其中某个字段就走索引”,而是严格按定义顺序从左到右逐列匹配,直到遇到范围查询(>、>=、、<code>BETWEEN、LIKE 前缀匹配除外)或跳过某列,后续列就失效了。
比如有联合索引 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_id,create_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_id是BIGINT,但传了字符串'123',会触发隐式转换,索引失效) - 运行
ANALYZE TABLE table_name更新统计信息 - 临时强制走索引测试:
SELECT ... FROM t USE INDEX (idx_user_status_time) WHERE ... - 注意:
SELECT *+ 联合索引覆盖不全时,可能回表代价高,优化器主动放弃索引
联合索引真正起效的前提,是你的查询条件和排序需求能被它「连续地、无跳跃地」覆盖。少一个等值条件,或多一个范围起点,后面列就成摆设——这点比单列索引容易误判得多。










