什么是索引下推和索引覆盖?

一、索引下推(Index Condition Pushdown, ICP)

1. 什么是索引下推?
  • 核心思想:在存储引擎层(如 InnoDB)提前过滤数据,减少不必要的回表操作。
  • 通俗解释:假设你有一个联合索引,查询时部分条件可以直接在索引层过滤掉不符合条件的记录,而不是把数据全部交给 MySQL 服务层再过滤。
2. 例子:没有索引下推 vs 有索引下推

假设有一张用户表 users,包含以下字段:

CREATE TABLE users (
    id INT PRIMARY KEY,
    age INT,
    city VARCHAR(20),
    name VARCHAR(20),
    INDEX idx_age_city (age, city)
);

现在执行查询:

SELECT * FROM users 
WHERE age > 20 AND city = 'Beijing';
情况1:没有索引下推(ICP关闭)
  1. 存储引擎的工作
    • 使用索引 idx_age_city,找到所有 age > 20 的记录。
    • 将这些记录的主键 id 返回给 MySQL 服务层。
  2. 服务层的工作
    • 根据主键 id 回表查询完整数据(包括 city)。
    • 再过滤出 city = 'Beijing' 的记录。

问题:存储引擎返回了大量 age > 20city 不是 Beijing 的记录,导致服务层需要回表并处理大量无用数据。

情况2:有索引下推(ICP开启)
  1. 存储引擎的工作
    • 使用索引 idx_age_city,直接过滤 age > 20 city = 'Beijing' 的记录。
    • 只返回满足两个条件的主键 id
  2. 服务层的工作
    • 根据主键 id 回表查询完整数据。

优化效果:存储引擎提前过滤了 city = 'Beijing',减少了回表次数和服务层处理的数据量。

3. 如何验证 ICP?

执行 EXPLAIN 查看执行计划:

EXPLAIN SELECT * FROM users 
WHERE age > 20 AND city = 'Beijing';

如果 Extra 列显示 Using index condition,说明 ICP 生效。

4. 适用场景
  • 查询条件包含联合索引中的列和非索引列(但非索引列过滤由存储引擎完成)。
  • 例如:联合索引 (a, b),查询条件为 a > 10 AND b = 'x' AND c = 'y',其中 c 是非索引列,但 b 的过滤可以下推。

二、索引覆盖(Covering Index)

1. 什么是索引覆盖?
  • 核心思想:查询所需的所有列都包含在索引中,无需回表查询主键索引。
  • 通俗解释:就像查字典时,你要查的单词和解释都在目录里,不需要翻到正文页。
2. 例子:没有索引覆盖 vs 有索引覆盖

继续使用 users 表,索引为 idx_age_city (age, city)

情况1:没有索引覆盖

查询:

SELECT * FROM users 
WHERE age = 25;
  • 流程
    1. 使用索引 idx_age_city 找到 age = 25 的记录的主键 id
    2. 根据 id 回表查询主键索引,获取所有字段(id, age, city, name)。
  • 问题:需要回表获取 name 字段,增加 I/O 操作。
情况2:有索引覆盖

查询:

SELECT age, city FROM users 
WHERE age = 25;
  • 流程
    1. 直接通过索引 idx_age_city 获取 agecity 的值。
    2. 无需回表查询主键索引。

优化效果:减少 I/O 和 CPU 消耗。

3. 如何验证索引覆盖?

执行 EXPLAIN

EXPLAIN SELECT age, city FROM users 
WHERE age = 25;

如果 Extra 列显示 Using index,说明索引覆盖生效。

4. 适用场景
  • 查询的列全部在索引中。
  • 例如:索引 (a, b, c),查询 SELECT a, b FROM table WHERE c = 10(需注意索引顺序是否能覆盖)。

三、联合使用案例

场景:同时利用 ICP 和索引覆盖

users 有索引 idx_age_city (age, city),执行查询:

SELECT id, age, city FROM users 
WHERE age > 20 AND city = 'Beijing';
  1. 索引覆盖id(主键)、agecity 都在索引 idx_age_city 中,无需回表。
  2. 索引下推:存储引擎直接过滤 age > 20city = 'Beijing',减少数据传输。

通过 EXPLAIN 可以看到:

  • Extra 列显示 Using index condition; Using index,说明同时用到了 ICP 和索引覆盖。

四、通俗总结

1. 索引下推(ICP)
  • 比喻:快递分拣员在仓库里直接扔掉不符合条件的包裹(如收件地址错误),而不是把所有包裹送到分拣中心再处理。
  • 核心:在存储引擎层提前过滤数据,减少“无效包裹”的传递。
2. 索引覆盖
  • 比喻:查字典时,目录里直接写了单词的解释,不需要翻到正文页。
  • 核心:避免回表查询,直接从索引中获取所有需要的数据。

五、注意事项

  1. 索引设计
    • 索引下推依赖联合索引的列顺序。
    • 索引覆盖要求查询的列全部在索引中。
  2. 性能权衡
    • 索引过多会影响写入性能。
  3. 验证工具
    • 使用 EXPLAIN 查看执行计划,重点关注 Extra 列。

六、实际应用建议

  1. 高频查询:优先为高频查询设计覆盖索引。
  2. 联合索引顺序:将过滤条件多的列放在索引前面。
  3. 减少回表:尽量通过覆盖索引避免 SELECT *
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值