联合索引的最左匹配到底匹配什么
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 *+ 联合索引覆盖不全时,可能回表代价高,优化器主动放弃索引
联合索引真正起效的前提,是你的查询条件和排序需求能被它「连续地、无跳跃地」覆盖。少一个等值条件,或多一个范围起点,后面列就成摆设——这点比单列索引容易误判得多。
