联合索引生效必须遵循最左前缀原则:where a = ? and c = ? 只能用到(a, b, c)索引的a列,c因跳过b而失效;where b = ? and c = ? 则完全不走索引;范围查询后字段不再参与索引查找,如a = ? and b > ? and c = ? 中c不生效。

联合索引不是“把WHERE里出现的字段堆一起”就能生效——顺序错了,90%的查询压根用不上。
为什么WHERE a = ? AND c = ?用不了(a, b, c)索引
因为B+树索引按字段顺序排序,(a, b, c)的结构是先排a、a相同再排b、a和b都相同再排c。跳过b就等于在有序目录里跳页码:你没法直接从“a=5”翻到“c='x'”,中间缺了定位锚点。
-
WHERE a = 1 AND b = 2 AND c = 3→ 全部命中 -
WHERE a = 1 AND c = 3→ 只有a生效,c被跳过,不参与索引查找 -
WHERE b = 2 AND c = 3→ 整个索引失效(最左缺失)
WHERE a = ? AND b > ? AND c = ?中c为什么没走索引
范围查询(>、、<code>BETWEEN、LIKE 'abc%')是索引生效的分水岭:它会让优化器“停在这一列”,右侧字段无法用于WHERE条件过滤,只能参与排序或覆盖(如果SELECT里只查索引列)。
-
INDEX (a, b, c)+WHERE a = 1 AND b > 10 AND c = 2→ a和b走索引查找,c不走(但若SELECT a,b,c,可能走覆盖) - 想让c也用于查找?要么把c挪到b前面(
(a, c, b)),要么确认b实际是IN(10,11,12)——MySQL会把它当等值处理 -
LIKE '%abc'或LIKE '%abc%'会让整个前缀失效,别指望它触发索引
怎么验证EXPLAIN里索引到底有没有真用上
光看CREATE INDEX成功没用,必须跑EXPLAIN盯三个字段:key、key_len、Extra。
-
key为空 → 没走索引 -
key有值但rows接近全表行数 → 索引建了但没起效(比如选择性太差,或条件没对齐最左前缀) -
key_len = 8(假设INT占4字节)→ 实际只用了前两个字段,第三个没命中 -
Extra里出现Using index才算真正覆盖;Using index condition表示用了ICP(索引条件下推),但仍有回表;Using where; Using index是常见误导项,它只说明WHERE用了索引,不代表覆盖
高频必查字段必须放最左,哪怕区分度更低
不要被“高区分度字段放前面更高效”的直觉带偏。联合索引的首要目标是匹配查询模式,不是最大化单列区分度。
-
user_id和tenant_id几乎每次查询都出现且是=,哪怕email唯一性更高,也不该抢第一位 - 如果常查
WHERE status = ? AND created_at > ?,但status只有3个值,MySQL可能直接放弃索引——这时得补一个前置的高频率字段,比如tenant_id = ? -
ORDER BY字段要紧接等值条件之后,且顺序、方向严格一致;否则Using filesort照旧
最易被忽略的一点:联合索引的维护成本真实存在——写入变慢、存储翻倍、冗余索引拖累DDL。上线前务必用真实数据量+线上慢查询日志验证,而不是只在测试库跑几条EXPLAIN。











