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

来源:这里教程网 时间:2026-02-28 20:51:55 作者:

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

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 *
+ 联合索引覆盖不全时,可能回表代价高,优化器主动放弃索引

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

相关推荐