联合索引需严格按查询条件最左连续字段顺序创建,如WHERE region='华东' AND status=1 AND create_time BETWEEN...应建INDEX(region, status, create_time);跳过最左字段、中间用范围条件或非前缀模糊匹配均导致失效。

联合索引能显著提升多维度筛选报表的查询速度,但前提是字段顺序与查询模式严格匹配;跳过最左字段、在中间字段用范围条件、或对最左字段做模糊前缀以外的匹配(如 LIKE '%abc'),都会导致索引失效。
联合索引字段顺序必须匹配WHERE条件的最左连续字段
报表常需支持「按区域+按状态+按时间范围」组合筛选,例如:WHERE region = '华东' AND status = 1 AND create_time BETWEEN '2025-01-01' AND '2025-12-31'。此时应建索引 INDEX(region, status, create_time),而非反过来。
- 有效:只查
region = '华东'、region = '华东' AND status = 1、完整三条件 —— 全部命中索引 - 失效:
status = 1单独查(跳过region);create_time > '2025-06-01'单独查(最左字段未出现) - 注意:
region LIKE '华%'是前缀匹配,仍可走索引;但region LIKE '%东'不行
范围条件之后的字段无法用于索引查找,但可能参与过滤
当联合索引为 (a, b, c),且查询含 a = 1 AND b > 10 AND c = 2 时,c = 2 不会用于定位索引节点,但 MySQL 会在 b > 10 扫出的数据块内直接比对 c 值,不回表也能过滤——这叫“索引条件下推”(ICP),MySQL 5.6+ 默认开启。
- 关键限制:
b > 10是范围操作,因此c字段不能用于缩小扫描范围,仅能减少最终返回行数 - 若写成
a = 1 AND b > 10 AND c > 20,则c > 20完全失效,等价于只用到(a, b)部分 - 报表中高频的「时间范围 + 状态枚举」组合,建议把状态放时间前:如
INDEX(region, status, create_time),避免时间范围一加,后面字段全废
覆盖索引能避免回表,对报表类查询尤其关键
报表 SQL 常需返回十多个字段,如果联合索引包含所有 SELECT 列和 WHERE 条件列,MySQL 就无需回主键索引查数据行,直接从二级索引页拿到全部结果——这就是覆盖索引。例如:
SELECT region, status, SUM(amount), COUNT(*)
FROM sales
WHERE region IN ('华东','华北') AND status = 1
GROUP BY region, status;
对应索引应为 INDEX(region, status, amount),且确保 amount 在索引中(作为包含列),否则 GROUP BY 后仍要回表取值。
- 检查是否覆盖:用
EXPLAIN看Extra是否含Using index,不是Using index condition - 注意:主键字段自动包含在二级索引中,所以
SELECT id, region, status只需INDEX(region, status)即可覆盖 - 别盲目加太多字段进索引——索引变宽会降低写入性能,也增加 Buffer Pool 压力
真正容易被忽略的是:报表查询往往带 ORDER BY 和 LIMIT,而联合索引的字段顺序还必须兼容排序需求。比如 ORDER BY region, create_time DESC,若索引是 (region, status, create_time),那 create_time 方向必须与查询一致(DESC 对应索引也得声明 DESC,MySQL 8.0+ 支持);否则即便走了索引,仍会触发 Using filesort。这不是小问题——报表翻页时,LIMIT 10000, 20 配合 filesort,性能断崖式下跌。



















