索引应按“等值字段→范围字段”顺序创建,等值字段放最左且优先高频高区分度字段;覆盖索引需使EXPLAIN显示Using index;避免IN/OR滥用、函数操作及低区分度字段前置。

WHERE 中多个字段组合查询,索引怎么建才不白建
多条件 WHERE 查询跑得慢,不是加了索引就万事大吉——顺序错了、字段多了、类型不匹配,索引直接变摆设。
核心原则:索引字段顺序必须严格匹配查询中「等值条件 → 最左前缀 → 范围/排序字段」的使用逻辑。比如 WHERE status = ? AND created_at > ? AND user_id = ?,status 和 user_id 都是等值,但只有把高频、高区分度、且出现在 SQL 最左侧的等值字段放前面,才能被有效利用。
- 先看执行计划:
EXPLAIN SELECT ...,重点盯key(是否用了索引)、key_len(用了索引的前几字节)、rows(扫描行数) - 等值字段(
=、IN)优先放索引最左;范围字段(>、BETWEEN)只能放在等值字段之后,且后面字段无法走索引 - 避免在索引字段上用函数或计算,比如
WHERE YEAR(created_at) = 2024会让created_at索引失效 -
IS NULL在某些版本能走索引,但IS NOT NULL大概率不行,别依赖
覆盖索引到底要包含哪些字段才真正“覆盖”
覆盖索引不是“把 SELECT 的字段全塞进索引里”,而是让 MySQL 仅靠索引 B+ 树的叶子节点就能返回全部所需数据,不用回表查聚簇索引。
判断标准很简单:执行 EXPLAIN 后,Extra 列出现 Using index,才算真正覆盖;如果出现 Using index condition,说明用了 ICP(索引下推),但仍有回表可能;出现 Using where; Using index 是常见混淆点——它只表示用了索引做 WHERE 过滤,并不等于覆盖。
- SELECT 列必须全部来自索引定义字段,包括主键(InnoDB 中主键自动包含在二级索引中,但显式写出来更安全)
- 如果查询含
ORDER BY或GROUP BY,对应字段也应纳入索引,否则可能触发 filesort - 不要盲目加太多字段进索引:每多一个字段,索引体积增大、写入变慢、缓存压力上升;
VARCHAR(500)字段尤其谨慎,考虑前缀索引或单独冗余 - 联合索引中字段顺序仍受 WHERE 条件约束——不能为了覆盖而把
ORDER BY字段硬塞到最左,否则 WHERE 可能完全用不上索引
IN 查询和 OR 条件对索引的影响很现实
IN 不一定走索引,OR 很可能让整个索引失效——这不是玄学,是优化器基于成本估算后的放弃。
当 IN 值过多(比如几百个)、或 IN 字段区分度极低(如 status IN (0,1))、或 IN 和其他范围条件混用时,MySQL 常常选择全表扫描。而 OR 更危险:哪怕两个字段各自有索引,WHERE a = 1 OR b = 2 默认不会合并使用两个索引(5.7+ 有 index merge,但不可控且性能不稳定)。
- 把
OR拆成UNION ALL(注意去重开销),通常比依赖 index merge 更可靠 -
IN值少且稳定时,确保该字段在索引最左或紧随等值字段后;值多时,考虑临时表或应用层分批 - 避免
IN (subquery),尤其是相关子查询,极易触发全表扫描;改用JOIN或物化临时表 - 区分度低的字段(如
gender、is_deleted)别单独建索引,也不适合放联合索引最左——除非搭配高区分度字段构成强过滤组合
时间范围 + 分页偏移大,为什么加了索引还慢
典型场景:WHERE created_at > '2024-01-01' ORDER BY id LIMIT 10000, 20。即使 created_at 有索引,LIMIT 10000, 20 仍要扫描前 10020 行,索引只加速了定位起点,没减少扫描量。
这不是索引设计问题,是查询模式本身反索引友好。此时覆盖索引也救不了——因为 id 是主键,created_at 索引叶子节点里虽然有 id,但排序仍需按 id 重新归并,优化器大概率放弃。
- 用游标分页替代
LIMIT offset, size:记录上一页最后的id,查WHERE created_at > ? AND id > ? ORDER BY created_at, id LIMIT 20 - 如果必须用偏移分页,且数据量不大,可先用覆盖索引查出所有匹配的
id,再用IN回查详情(注意IN长度限制) - 对高频时间范围查询,考虑按月/周分区表,配合
PRUNE减少扫描范围 - 别给
created_at单独建索引还幻想它能扛住分页——它只解决“从哪开始”,不解决“跳过多少”


















