联合索引最左匹配指严格按定义顺序逐列匹配,遇范围查询或跳过某列则后续列失效;order by/group by需与索引前缀完全一致才能避免filesort;覆盖索引要求select列全在索引中且满足最左匹配。

联合索引的最左匹配到底匹配什么
联合索引不是“只要条件里有索引列就走索引”,而是严格按定义顺序逐列匹配,直到遇到范围查询(>、>=、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'→ 完全不走这个索引(没用到最左列user_id)
ORDER BY 和 GROUP BY 怎么借力联合索引
如果 ORDER BY 或 GROUP BY 的字段顺序和联合索引前缀完全一致,且无混合 ASC/DESC(MySQL 8.0+ 支持部分混合,但多数场景仍建议统一),就能避免 Using filesort 或 Using temporary。
例如查询:SELECT * FROM orders WHERE user_id = 1001 ORDER BY status, create_time DESC,配合索引 INDEX idx_uid_status_ct (user_id, status, create_time):
- ✅
user_id用于过滤,status和create_time天然满足排序需求 - ❌ 若索引是
(user_id, create_time, status),则ORDER BY status, create_time无法复用索引排序,仍会触发Using filesort - ⚠️
ORDER BY status ASC, create_time DESC在 MySQL 5.7 中基本无效;8.0+ 需确认执行计划中是否出现Using index而非Using filesort
覆盖索引减少回表的实操边界
当 SELECT 列全部包含在联合索引中,MySQL 可直接从索引页返回数据,无需回主键 B+ 树查行记录——这就是覆盖索引。它对高并发、IO 瓶颈明显的场景提升显著。
但要注意几个现实约束:
- 索引列顺序仍需满足最左匹配,否则即使字段全在索引里,也可能因无法定位而退化为全索引扫描
-
TEXT、BLOB类型不能建索引,所以含这类字段的SELECT *几乎不可能被覆盖 - 联合索引越宽,写入开销越大,单行索引体积上升,缓冲池利用率可能下降;别为了覆盖把 5 个字段全塞进一个索引
- 验证是否真正覆盖:看
EXPLAIN的Extra字段是否含Using index(注意不是Using index condition)
联合索引 vs 单列索引,什么时候该合并
不是所有多条件查询都适合建联合索引。如果 WHERE a = ? AND b = ? 频繁,但 WHERE a = ? 和 WHERE b = ? 同样高频,那单独建两个单列索引 + index_merge 可能更灵活(尤其当数据分布倾斜时)。
但要注意:
- MySQL 默认关闭
index_merge_intersection,且实际优化器常不选它;除非明确SET optimizer_switch='index_merge=on'并验证执行计划 - 联合索引能服务“前缀子集”,比如
(a,b,c)可支撑a、a,b、a,b,c查询;单列索引无法共享这种优势 - 线上表已有多个单列索引时,盲目合并可能让原有慢查询更慢——先用
pt-index-usage或慢日志分析真实命中情况,再决策
最易被忽略的一点:联合索引中列的区分度排序影响不大,但过滤强度排序很关键——把等值查询高选择性的列放前面,比放低选择性列更能快速收敛结果集。










