“联合索引遇到范围条件后,后续列就失效”把几种作用混在了一起。以 InnoDB 索引 (a,b,c) 和查询 WHERE a=1 AND b>=10 AND c=3 为例,a=1 与 b>=10 可构造索引连续扫描范围;范围列 b 之后的 c 通常不能继续把同一范围精确切成更小的 B+ 树区间,但 c 并非一定完全无用。
ICP 过滤: 若 c 位于二级索引中且条件满足下推条件,存储引擎可扫描索引条目时先检查 c=3,只对候选条目回表。EXPLAIN 的 Using index condition 可提示 ICP。它减少回表,不等于消除了索引扫描。
覆盖读取: 若查询只需 a,b,c 等索引中已有列,查询可能直接从索引返回,避免回表。此时即使 c 没用于缩小范围,也仍可能因覆盖而有价值。覆盖索引增加叶子宽度和写入成本,应控制列数。
排序: 索引列有序不代表任意 ORDER BY 都能避免排序。对 (a,b,c),固定 a 后,按 b,c 的顺序读取有机会利用索引顺序;但 WHERE a=1 AND b>=10 ORDER BY c 中结果按 b 再按 c 排列,并非全局按 c,通常仍要额外排序。是否 filesort 以计划为准。
EXPLAIN SELECT c FROM t WHERE a=1 AND b>=10 AND c=3;EXPLAIN SELECT a,b,c FROM t WHERE a=1 AND b>=10 AND c=3;EXPLAIN SELECT * FROM t WHERE a=1 AND b>=10 ORDER BY c;第一条关注范围与 ICP;第二条可观察覆盖可能性;第三条观察排序。MySQL 8.0 中计划仍由成本模型、统计信息和数据分布决定。EXPLAIN ANALYZE 会实际执行查询,使用前应确认语句和负载安全。
追问
范围列后的条件一定不能用索引吗?
不一定。它通常不能进一步构造连续范围,但可由 ICP 检查,也可能用于覆盖读取;看 Extra、key 和实际行数。
ICP 是不是覆盖索引?
不是。ICP 可先过滤再决定是否回表;覆盖索引表示所需列都能由索引提供,通常无需回表。
(a,b,c) 能支持 WHERE a=1 AND b>2 ORDER BY c 吗?
它能用于 a、b 的范围查找,但结果按 b、c 排序,通常不能保证全局 c 顺序;用 EXPLAIN 检查是否额外排序。