联合索引到底能不能用上,只看最左字段有没有被等值过滤
MySQL 不会因为你写了
b = 2 AND a = 1就自动“倒着走”索引。它只认最左边那个字段是否出现在查询条件中、且是等值(或
IN)匹配。
只要
a没出现在 WHERE 条件里,哪怕你建的是
INDEX(a, b, c),这条语句就直接退化为全表扫描:
SELECT * FROM t WHERE b = 2→
type=ALL,
key=NULL。 ✅ 正确写法:
WHERE a = 1、
WHERE a = 1 AND b > 10、
WHERE a IN (1,2,3) AND b = 5❌ 错误写法:
WHERE b = 2、
WHERE c = 3、
WHERE b = 2 AND c = 4⚠️ 注意:
WHERE a = 1 AND c = 3只能用上
a,
c完全无效 —— 中间跳过了
b,后续字段全部失效
ORDER BY 能不能走索引,取决于排序字段是否在最左前缀连续段内
联合索引不是“包含这些字段就能排序”,而是要求:排序字段必须紧接在过滤字段之后,中间不能断档,也不能被范围查询截断。
比如有
INDEX(user_id, create_time):
WHERE user_id = 123 ORDER BY create_time DESC✅ 无 filesort
WHERE user_id > 100 ORDER BY create_time DESC❌
user_id是范围,
create_time失效,必 filesort ✅ 能避免
Using filesort:
WHERE a = 1 ORDER BY b、
WHERE a = 1 AND b = 2 ORDER BY c❌ 必然触发
Using filesort:
WHERE a = 1 ORDER BY c(跳过
b)、
WHERE a = 1 AND b > 10 ORDER BY c(
b是范围,
c无序) ? 小技巧:如果常查
WHERE status = ? ORDER BY updated_at,优先建
INDEX(status, updated_at),别指望两个单列索引拼起来能排序
字段顺序怎么排?别按字母,要按区分度 + 查询模式
高区分度字段放最左,不是为了“好看”,是为了让 B+ 树第一层就能切掉最多数据。
比如
gender只有男/女,建
INDEX(gender, age)相当于先分两桶,再每桶里筛年龄 —— 第一层几乎没过滤能力;反过来建
INDEX(age, gender),先按年龄切成几十段,再每段里筛性别,效率高得多。 ? 验证选择性:
SELECT COUNT(DISTINCT col)/COUNT(*) FROM table,越接近 1 越好 ? 查看高频查询:如果 80% 的查询都带
WHERE tenant_id = ?,那
tenant_id就该放最左,哪怕它区分度不如
id? 避免默认值为
NULL:联合索引中任意一列含
NULL,该行就不进索引 —— 设计表时尽量用
NOT NULL DEFAULT ''或
0
EXPLAIN 显示 type=ALL 或 Using filesort,八成是索引没被“完整驱动”
别急着加索引,先看
EXPLAIN的
key和
key_len字段:
如果
key是你的联合索引名,但
key_len很小(比如预期 12,实际只有 4),说明只用了第一个字段;
如果
key=NULL,那连最左字段都没命中,索引等于白建。 ? 实操建议:用
SHOW INDEX FROM table_name确认索引字段顺序和长度 ? 测试时别只跑单条 SQL:用真实业务参数,比如
WHERE a = 1 AND b = 2在测试数据里可能命中,但线上
a = 1占比 95%,那就几乎不走
b⚠️ 最容易被忽略的一点:
OR条件会让整个联合索引失效,除非每个
OR分支都有独立索引 —— 别试图靠
INDEX(a,b)支持
WHERE a = 1 OR b = 2
