Skip to content

联合索引 A= 10 B > 100 C > 50 这种怎么查?

约 774 字大约 3 分钟

MySQL字节

2025-03-27

⭐ 题目日期:

字节 - 2024/9/3

📝 题解:

在联合索引 (A, B, C) 的场景下,针对查询条件 A=10 AND B>100 AND C>50,数据库的查询流程和索引使用情况如下:


一、索引使用分析

  1. 最左前缀原则
    1. A=10 是等值查询,联合索引的第一列被完全命中,索引可高效定位到所有 A=10 的连续数据块。
    2. B>100 是范围查询,索引的第二列 B 部分生效(仅定位到 B>100 的起始位置)。
    3. C>50 无法利用索引,因为 B 的范围查询导致后续索引列 (C) 的有序性被破坏,数据库需在结果集中逐行过滤 C>50 的条件。
  2. 索引扫描范围
    1. 数据库会扫描联合索引中 A=10B>100 的所有记录,然后对这些记录的 C 字段进行过滤。

二、查询执行流程

  1. 索引定位
    1. 在联合索引树中,快速定位到 A=10 的起始位置。
    2. A=10 的范围内,找到 B>100 的最小值,开始顺序扫描。
  2. 数据过滤
    1. 对满足 A=10 AND B>100 的每一行,检查 C>50 是否成立。
    2. 符合条件的行将被返回或进一步处理(如 JOIN、聚合等)。
  3. 终止条件
    1. 当扫描到 A≠10B≤100 时停止(因索引按 (A, B, C) 排序)。

三、执行计划示例(EXPLAIN 输出)

EXPLAIN SELECT * FROM table WHERE A=10 AND B>100 AND C>50;

可能的输出结果:

img


四、优化建议

1. 调整索引顺序

  • 问题:原索引 (A, B, C) 无法有效覆盖 C 的条件。
  • 改进:若查询中 C 是高频过滤条件,可尝试将等值列前置,范围列后置:
-- 假设 C 是等值查询(如 C=50),但本例中 C 是范围,无法直接优化
CREATE INDEX idx_A_C_B ON table(A, C, B);

2. 使用覆盖索引Covering Index

  • 方法:将查询所需的字段全部包含在索引中,避免回表。
CREATE INDEX idx_A_B_C_covering ON table(A, B, C) INCLUDE (other_columns);

3. 索引条件下推(Index Condition Pushdown, ICP**)**

  • 优化原理:在存储引擎层提前过滤 C>50,减少回表次数。
  • 要求:数据库支持 ICP(如 MySQL 5.6+ 的 InnoDB)。
  • 效果Extra 列显示 Using index condition

4. 分页查询优化

  • 场景:若需分页(如 LIMIT 1000, 10),避免深分页:
-- 通过子查询或游标优化
SELECT * FROM table 
WHERE A=10 AND B>100 AND C>50 AND id > last_id 
ORDER BY id LIMIT 10;

五、总结

  • 索引生效范围:联合索引 (A, B, C) 中,A=10B>100 可触发索引范围扫描,但 C>50 需逐行过滤。
  • 优化方向
    • 调整索引顺序(需结合查询模式)。
    • 利用覆盖索引减少回表开销。
    • 启用索引条件下推(ICP)提前过滤。
  • 执行代价:扫描行数取决于 A=10 AND B>100 的数据量,需监控 rows 字段并控制结果集规模。