mysql进阶一
你这个问题问得非常好,很多文章在讲 Index Condition Pushdown(ICP,索引下推) 的时候都举这个例子,但没有解释清楚,导致大家误以为:
“用了联合索引 = 用了 ICP”
实际上,这是两回事。
先说结论
对于:
SELECT *
FROM user
WHERE age = 20
AND name LIKE 'Tom%';
联合索引:
(age, name)
确实能用到联合索引。
但是:
是否使用 ICP,关键在于:
name LIKE 'Tom%'这个条件是在“存储引擎层”过滤,还是在“Server 层”过滤。
ICP 优化的是:
减少回表次数
而不是:
决定能不能走索引
没有 ICP 的流程
假设:
CREATE INDEX idx_age_name ON user(age,name);
索引长这样:
(age,name) 主键id
--------------------------
20,Tom 1
20,Tommy 2
20,Tony 3
20,Alice 4
20,Bob 5
21,Tom 6
查询:
SELECT *
FROM user
WHERE age=20
AND name LIKE 'Tom%';
MySQL 5.5 以前(没有 ICP):
第一步:
利用联合索引找到:
age=20
对应范围:
20,Tom
20,Tommy
20,Tony
20,Alice
20,Bob
第二步:
全部回表:
id=1
id=2
id=3
id=4
id=5
去聚簇索引找整行数据:
SELECT *
第三步:
Server 层判断:
name LIKE 'Tom%'
保留:
Tom
Tommy
过滤:
Tony
Alice
Bob
回表次数:
5 次
有 ICP 的流程
MySQL 5.6+
EXPLAIN:
Using index condition
表示启用了 ICP。
执行过程:
第一步还是一样:
找到:
age=20
对应范围:
20,Tom
20,Tommy
20,Tony
20,Alice
20,Bob
第二步:
因为:
name 在联合索引里面
所以:
name LIKE 'Tom%'
可以在二级索引叶子节点上直接判断。
过滤掉:
Tony
Alice
Bob
保留:
Tom
Tommy
第三步:
只有符合条件的:
id=1
id=2
才回表。
回表次数:
2 次
为什么说是“下推”?
原来:
存储引擎
↓
返回所有 age=20 的记录
Server 层
↓
判断 name LIKE
变成:
存储引擎
↓
判断 age=20
判断 name LIKE
Server 层
↓
拿最终结果
即:
把原本在 Server 层执行的条件,
下推(Push Down)到存储引擎层执行。
所以叫:
Index Condition Pushdown
你这里真正困惑的是:
既然
(age,name)本来就能匹配name,为什么还要 ICP?
答案是:
因为:
SELECT *
导致:
联合索引不是覆盖索引
必须回表。
ICP 的意义就在于:
先利用索引里的 name 过滤,
再决定哪些记录需要回表。
而不是:
所有 age=20 的都回表。
如果是覆盖索引呢?
例如:
SELECT age,name
FROM user
WHERE age=20
AND name LIKE 'Tom%';
由于:
(age,name)
已经覆盖:
SELECT age,name
执行过程:
直接从联合索引返回结果
根本:
不需要回表
此时:
ICP 的意义就很小了。
EXPLAIN 通常显示:
Using where; Using index
再举一个更典型的 ICP 场景
索引:
(age,name)
查询:
SELECT *
FROM user
WHERE age > 20
AND name='Tom';
没有 ICP:
找到所有 age>20
↓
全部回表
↓
Server 判断 name='Tom'
有 ICP:
找到 age>20
↓
在索引上判断 name='Tom'
↓
只有 Tom 才回表
收益更明显。
怎么判断是否用了 ICP?
看:
EXPLAIN
SELECT *
FROM user
WHERE age=20
AND name LIKE 'Tom%';
如果:
Extra:
Using index condition
说明:
用了 ICP
如果:
Using where
则没有。
最后一句话总结
联合索引决定“能否利用索引定位数据”;ICP 决定“能否利用索引中的字段提前过滤数据、减少回表”。
所以:
WHERE age=20
AND name LIKE 'Tom%'
在 (age,name) 上:
- 联合索引负责找到
age=20的索引范围; - ICP 利用索引中的
name在回表之前过滤掉不满足LIKE 'Tom%'的记录; - 最终减少回表次数,提高性能。
这也是为什么很多人会说:
ICP 本质上优化的不是“查索引”,而是“少回表”。
浙公网安备 33010602011771号