mysql优化-mysql索引下推
它的官方名称叫 Index Condition Pushdown,简称 ICP。
核心目的
索引下推的核心目的是减少存储引擎层需要回表查询的次数,从而提升查询性能,特别是对于那些无法完全在索引中筛选数据行的查询。
工作原理(对比开启/关闭ICP)
想象一个场景:你有一张表 users
,上面有一个联合索引 idx_age_city (age, city)
。
现在你要执行这样一个查询:
SELECT * FROM users WHERE age > 25 AND city = 'Beijing';
1. 在没有开启 ICP 的情况下(MySQL 5.6 之前)
存储引擎(如 InnoDB):
使用索引
idx_age_city
找到所有满足age > 25
条件的记录的主键值 (或定位到数据)。因为
city
虽然是索引的第二列,但在age > 25
(范围条件)的情况下,存储引擎默认不能使用索引中city
列的条件进行进一步的过滤(索引的最左前缀原理,范围条件会“截断”后续列的索引查找)。存储引擎需要根据每一个满足
age > 25
的主键值,执行回表操作,读取完整的数据行(完整的 row)。
MySQL 服务器层:
接收到存储引擎返回的所有满足
age > 25
的完整数据行。服务器层自己负责应用
WHERE
条件中剩下的city = 'Beijing'
进行过滤。最终返回符合所有条件
(age > 25 AND city = 'Beijing')
的数据给客户端。问题: 很多
age > 25
的行,其city
可能不是'Beijing'
。但存储引擎仍然把它们全部读出来并传给服务器层,造成了大量不必要的回表 I/O 和网络传输。
2. 在开启 ICP 的情况下(MySQL 5.6 及之后默认开启)
存储引擎(如 InnoDB):
和之前一样,使用索引
idx_age_city
找到所有满足age > 25
条件的记录。关键区别来了:
MySQL 服务器层会将
WHERE
子句中的过滤条件(尤其是那些属于该索引但无法被索引查找直接使用的部分,如本例中city = 'Beijing'
)“下推” 到存储引擎层。存储引擎在找到满足
age > 25
的索引条目后,不会立即回表!存储引擎直接在索引(通常是二级索引的叶子节点,存储了
(age, city, 主键)
)上检查city
列是否等于'Beijing'
。只有当一个索引条目同时满足
age > 25
和city = 'Beijing'
(或者说满足下推的条件)时,存储引擎才会执行回表操作读取完整数据行。
MySQL 服务器层:
只接收存储引擎传回的、已经初步满足
age > 25 AND city = 'Beijing'
条件的完整数据行。服务器层再进行一些 ICP 无法处理的其他条件检查(比如涉及非索引列的计算或函数等),然后返回结果。
优势: 显著减少了回表操作和传输给服务器层的数据量。 很多
age > 25
但city
不是'Beijing'
的行,在存储引擎层就被过滤掉了,根本不需要回表读取数据行,也不需要传输到服务器层处理。
图示简化流程
没有ICP:
索引(找 age>25) -> 回表取行 -> 给服务器 -> 服务器过滤 city='Beijing'开启ICP:
索引(找 age>25) -> 在索引上立即检查 city='Beijing'? -> Yes -> 回表取行 -> 给服务器 -> 服务器检查其他条件|VNo, 跳过此条!
ICP 能生效的关键点
索引类型: ICP 主要适用于二级索引(Secondary Index)。主键索引(聚簇索引)本身包含了完整的数据行,无需回表,因此 ICP 对其无效。
查询类型: 对
InnoDB
表有效。作用范围: 适用于
SELECT
、UPDATE
和DELETE
语句中需要访问完整表行的情况。如果查询只需要索引列(覆盖索引),那么即使存在其他条件,也不需要回表,ICP 的效果可能不明显或没有用武之地(因为数据已经通过索引返回了)。条件位置:
被下推的条件部分必须能够通过索引列来评估。
WHERE
条件被划分为两部分:索引条件 (Index Condition): 那些与索引列相关、能被存储引擎在索引上直接评估的条件(即使不能用于索引查找本身,如非最左前缀或等值匹配后的范围列)。
表级条件 (Table Condition): 那些不能通过索引评估的条件(如非索引列、索引列的复杂函数计算等)。
ICP 只处理索引条件部分。
如何判断查询是否使用了 ICP?
使用 EXPLAIN
查看你的 SQL 执行计划。如果在 Extra
列中看到 Using index condition
,就表明 MySQL 对该查询使用了索引下推。
EXPLAIN SELECT * FROM users WHERE age > 25 AND city = 'Beijing';
可能的 Extra 输出:
Using index condition # 这代表使用了ICP
Using where # 这代表服务器层应用了额外的表级条件过滤
性能提升
效果非常显著,尤其是当第一个索引列是范围条件且满足该范围条件的行数很多,但第二个索引列的条件具有高选择性(能过滤掉大量行)时。
官方文档(MySQL 8.0)提到在某些场景下性能提升可达几十倍甚至几百倍。
总结
索引下推(ICP)是 MySQL 一项重要的查询优化技术,通过在存储引擎层对索引条件进行早期过滤,极大限度地减少了不必要的回表 I/O 操作和数据传输量,从而显著提升查询性能。它特别适用于使用联合索引时,WHERE
子句中包含第一个索引列的范围条件以及后续索引列的等值/范围等条件的情况。理解 ICP 对于优化慢查询至关重要。