mysql联合索引怎么用_mysql索引规则解析

2次阅读

联合索引能否使用只取决于最左字段是否在where中等值匹配,如index(a,b,c)中a未出现则全表扫描;order by能否走索引要求排序字段紧接过滤字段且无断层或范围截断;字段顺序应按区分度和查询频率优化,避免NULL

mysql联合索引怎么用_mysql索引规则解析

联合索引到底能不能用上,只看最左字段有没有被等值过滤

mysql 不会因为你写了 b = 2 AND a = 1 就自动“倒着走”索引。它只认最左边那个字段是否出现在查询条件中、且是等值(或 IN)匹配。
只要 a 没出现在 WHERE 条件里,哪怕你建的是 INDEX(a, b, c),这条语句就直接退化为全表扫描:
select * FROM t WHERE b = 2type=ALLkey=NULL

  • ✅ 正确写法:WHERE a = 1WHERE a = 1 AND b > 10WHERE a IN (1,2,3) AND b = 5
  • ❌ 错误写法:WHERE b = 2WHERE c = 3WHERE b = 2 AND c = 4
  • ⚠️ 注意:WHERE a = 1 AND c = 3 只能用上 ac 完全无效 —— 中间跳过了 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 DESCuser_id 是范围,create_time 失效,必 filesort

  • ✅ 能避免 using filesortWHERE a = 1 ORDER BY bWHERE a = 1 AND b = 2 ORDER BY c
  • ❌ 必然触发 Using filesortWHERE a = 1 ORDER BY c(跳过 b)、WHERE a = 1 AND b > 10 ORDER BY cb 是范围,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,八成是索引没被“完整驱动”

别急着加索引,先看 EXPLAINkeykey_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
text=ZqhQzanResources