外观
联合索引 A= 10 B > 100 C > 50 这种怎么查?
⭐ 题目日期:
字节 - 2024/9/3
📝 题解:
在联合索引 (A, B, C)
的场景下,针对查询条件 A=10 AND B>100 AND C>50
,数据库的查询流程和索引使用情况如下:
一、索引使用分析
- 最左前缀原则:
A=10
是等值查询,联合索引的第一列被完全命中,索引可高效定位到所有A=10
的连续数据块。B>100
是范围查询,索引的第二列B
部分生效(仅定位到B>100
的起始位置)。C>50
无法利用索引,因为B
的范围查询导致后续索引列 (C
) 的有序性被破坏,数据库需在结果集中逐行过滤C>50
的条件。
- 索引扫描范围:
- 数据库会扫描联合索引中
A=10
且B>100
的所有记录,然后对这些记录的C
字段进行过滤。
- 数据库会扫描联合索引中
二、查询执行流程
- 索引定位:
- 在联合索引树中,快速定位到
A=10
的起始位置。 - 在
A=10
的范围内,找到B>100
的最小值,开始顺序扫描。
- 在联合索引树中,快速定位到
- 数据过滤:
- 对满足
A=10 AND B>100
的每一行,检查C>50
是否成立。 - 符合条件的行将被返回或进一步处理(如
JOIN
、聚合等)。
- 对满足
- 终止条件:
- 当扫描到
A≠10
或B≤100
时停止(因索引按(A, B, C)
排序)。
- 当扫描到
三、执行计划示例(EXPLAIN 输出)
EXPLAIN SELECT * FROM table WHERE A=10 AND B>100 AND C>50;
可能的输出结果:
四、优化建议
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=10
和B>100
可触发索引范围扫描,但C>50
需逐行过滤。 - 优化方向:
- 调整索引顺序(需结合查询模式)。
- 利用覆盖索引减少回表开销。
- 启用索引条件下推(ICP)提前过滤。
- 执行代价:扫描行数取决于
A=10 AND B>100
的数据量,需监控rows
字段并控制结果集规模。