联合索引仅支持最左前缀匹配:a=1、a=1 AND b=2、a=1 AND b=2 AND c=3可走索引;b=2或a=1 AND c=3则无法充分利用。字段顺序应按选择性与查询模式排列,高区分度字段靠左,排序字段靠右。

联合索引能用上的查询条件长什么样?
只有满足「最左前缀匹配」的 WHERE 条件,才能真正走 INDEX(a, b, c) 这类联合索引。不是“包含这些字段就行”,而是必须从最左边开始、连续使用。
-
a = 1✅ 走索引(只用 a) -
a = 1 AND b = 2✅ 走索引(a + b) -
a = 1 AND b = 2 AND c = 3✅ 走索引(全列匹配) -
b = 2❌ 不走索引(跳过了 a) -
a = 1 AND c = 3❌ 只用上 a,c 被跳过,b 没参与 →b字段无法利用索引排序,c实际失效 -
a IN (1,2) AND b = 3✅ 走索引(IN算等值,仍满足最左前缀)
注意:MySQL 查询优化器会自动调整 WHERE 子句中字段顺序(比如把 b = 2 AND a = 1 改成 a = 1 AND b = 2),但前提是所有字段都在同一层级且无函数/计算干扰 —— 别依赖它来“救场”,自己写对才是稳的。
联合索引字段顺序怎么排才不翻车?
顺序不是按字母或出现频率排,而是按「选择性」和「查询模式」定:高区分度字段放前面,高频过滤字段靠左,排序/分组字段尽量靠右。
- 错误示例:
INDEX(gender, age)——gender只有男/女,索引树第一层就分裂成两支,后续age再怎么细分也意义不大 - 正确示例:
INDEX(age, gender)—— 先按年龄精细切分,再在每个年龄段里筛性别,B+ 树搜索路径更短 - 如果常查
WHERE user_id = ? ORDER BY create_time DESC,优先建INDEX(user_id, create_time),而不是分开两个单列索引
验证选择性:可用 SELECT COUNT(DISTINCT col)/COUNT(*) FROM table 粗估;值越接近 1,该列越适合作为联合索引首列。
为什么加了联合索引,EXPLAIN 还显示 type=ALL 或 Using filesort?
EXPLAIN 中 type=ALL 表示全表扫描,Extra: Using filesort 表示 MySQL 没法用索引完成排序 —— 这两类问题往往不是没建索引,而是索引没被“完整驱动”。
-
WHERE a = 1 ORDER BY b+INDEX(a, b)✅ 能避免 filesort -
WHERE a = 1 ORDER BY c+INDEX(a, b, c)❌c不在索引前缀连续段内,无法利用排序结构,仍 filesort -
SELECT * FROM t WHERE b = 2+INDEX(a, b, c)❌ 最左没匹配,直接退化为全表扫 -
WHERE a = 1 AND b > 10 ORDER BY c+INDEX(a, b, c)⚠️b是范围查询,c的排序失效(B+ 树中,a 相同、b > 10 的 c 值是无序的)
关键点:范围查询(>, , BETWEEN, LIKE 'abc%')之后的字段,只能用于索引查找,不能用于排序或精确匹配。
什么时候该用联合索引,而不是多个单列索引?
当你的高频查询同时命中多个字段,且存在固定组合时,联合索引几乎总是优于多个单列索引 —— 因为 MySQL 一般一次只用一个索引(除非开启 index_merge,但代价高、不可控)。
SELECT * FROM orders WHERE user_id = 123 AND status = 'paid' AND created_at > '2025-01-01';
- 错:分别建
INDEX(user_id)、INDEX(status)、INDEX(created_at)→ 优化器大概率只选一个,其余条件回表过滤,慢 - 对:建
INDEX(user_id, status, created_at)→ 三条件一次性定位,且若只查这三列,还能覆盖索引(Extra: Using index) - 更优:如果
status只有 3–4 个值,而user_id是主键级区分度,就把user_id放最左;再根据实际数据分布微调
别忘了删冗余索引:比如已有 INDEX(a, b, c),再单独建 INDEX(a) 或 INDEX(a, b) 就是浪费 —— 写入开销白增,优化器还可能选错。










