首页 >> 基础教程

mysql中什么是索引下推?

        在 MySQL 中,索引下推(Index Condition Pushdown, ICP) 是一项从 MySQL 5.6 版本开始引入的重要查询优化技术。它的核心目的是减少存储引擎层与服务器层之间不必要的数据传输(尤其是回表次数),从而显著提升某些查询的性能,特别是对联合索引上的范围查询和包含非等值条件的查询。

核心思想:将过滤条件“下推”到存储引擎层

在理解 ICP 之前,先看传统的查询流程(无 ICP):

  1. 存储引擎层:

    1. 根据索引(通常是二级索引)查找满足索引最左前缀条件的记录(例如 WHERE last_name = 'Smith')。

    2. 对于找到的每一条索引记录,不管该记录是否满足 WHERE 子句中剩下的其他条件(例如 AND first_name LIKE 'J%' AND age > 30,都根据索引中的主键值(或聚集索引键)执行一次回表操作,读取完整的行数据。

    3. 将所有读取到的完整行数据返回给 MySQL 服务器层。

  2. 服务器层:

    • 接收存储引擎返回的所有完整行数据。

    • 对这些行数据应用 WHERE 子句中剩下的所有条件(first_name LIKE 'J%' AND age > 30)进行过滤。

    • 只保留真正满足所有条件的行。

问题: 传统方式中,存储引擎层会返回所有满足最左前缀条件(last_name = 'Smith')的行,即使其中很多行根本不满足其他条件(如 first_name 不以 J 开头或 age 太小)。这导致了大量不必要的回表操作和完整行数据的传输,浪费 I/O 和 CPU 资源。

ICP 如何工作?

索引下推优化改变了这个流程:

  1. 存储引擎层:

    • 仍然根据索引最左前缀条件(last_name = 'Smith')查找记录。

    • 关键点:对于找到的每一条索引记录,存储引擎会先检查 WHERE 子句中那些 可以利用当前索引进行评估 的其余部分条件(first_name LIKE 'J%' AND age > 30)是否满足。

      • 这些条件必须只涉及索引中包含的列(例如,如果索引是 (last_name, first_name, age),那么 first_name LIKE 'J%' 和 age > 30 都可以在索引记录中直接检查,无需回表)。

    • 只有当前索引记录同时满足最左前缀条件  这些下推的索引条件时,存储引擎才会执行回表操作,读取完整的行数据。

    • 将满足所有索引层条件的完整行数据返回给服务器层。

  2. 服务器层:

    • 接收存储引擎返回的行数据(这些数据已经通过了索引层的过滤)。

    • 应用 WHERE 子句中剩余的、无法被索引下推处理的条件(通常是那些不包含在索引中的列的条件)进行最终过滤(如果还有的话)。

ICP 带来的好处

  1. 显著减少回表次数: 存储引擎在回表前就用索引中的列过滤掉了大量不满足条件的记录,避免了为这些无效记录访问主键(聚集索引)的开销。这是性能提升最主要的来源。

  2. 减少数据传输: 服务器层需要接收和处理的行数大大减少。

  3. 降低 CPU 开销: 服务器层需要评估 WHERE 条件的次数减少。

适用 ICP 的条件

  1. 表访问方式: 查询需要通过二级索引进行访问(type 在 EXPLAIN 输出中通常是 refeq_refrangeindex_merge 等)。

  2. WHERE 条件: WHERE 条件包含:

  3. 存储引擎支持: InnoDB 和 MyISAM 引擎都支持 ICP。

    1. 使用索引最左前缀的条件(用于定位索引扫描的起点和范围)。

    2. 以及额外的条件涉及索引中的列,但这些条件本身不能直接用于缩小扫描范围(范围扫描之后的列)。常见于:

      1. 联合索引中第一列是等值/范围,后面列是非等值条件(如 =><BETWEENLIKE 'prefix%')。

      2. 联合索引中非第一列的条件(但前提是第一列的条件触发了范围扫描)。

  4. 非覆盖索引: 如果查询所需的所有列都包含在索引中(覆盖索引),则查询本身就不需要回表,ICP 的效果相对不那么显著(但索引层面的过滤仍然发生)。ICP 在需要回表的场景下收益最大。

  5. 子查询、存储函数等: 某些复杂条件(如涉及子查询、存储函数的条件)可能无法下推。

如何确认 ICP 被使用?

使用 EXPLAIN 语句查看查询执行计划。如果在 Extra 列中看到 Using index condition,就表示该查询使用了索引下推优化。

EXPLAIN SELECT * FROM employees 
WHERE last_name = 'Smith' AND first_name LIKE 'J%' AND age > 30;

假设表 employees 有索引 idx_name_age (last_name, first_name, age)

  • 无 ICP:

    • 存储引擎通过索引找到所有 last_name = 'Smith' 的记录。

    • 对 每一条 这样的记录都回表读取完整行。

    • 服务器层检查这些完整行是否满足 first_name LIKE 'J%' AND age > 30

  • 有 ICP:

    • 存储引擎通过索引找到所有 last_name = 'Smith' 的记录。

    • 对于 每一条 这样的索引记录(包含 last_namefirst_nameage 值),直接在存储引擎层检查 first_name LIKE 'J%' AND age > 30 是否成立

    • 只有当 last_name = 'Smith'  first_name LIKE 'J%'  age > 30 都满足时,才回表读取完整行

    • 服务器层接收到的就是已经过滤过的行(可能还要检查不在索引中的条件)。

       索引下推(ICP)是 MySQL 优化器的一项强大功能,它通过将 WHERE 子句中索引列的部分过滤条件“下推”到存储引擎层执行在索引扫描过程中尽早过滤掉不符合条件的记录,从而避免了大量不必要的回表操作和完整行数据的传输,极大地提升了包含联合索引和非等值条件的查询性能。检查 EXPLAIN 输出中的 Using index condition 是判断 ICP 是否生效的关键。它是优化 MySQL 查询效率,尤其是涉及联合索引范围查询时的重要利器。

最新文章
mysql分页问题2025-08-04
千万数据先insert和先建索引哪个快2025-08-04
MySQL 中大小表关联查询如何优化2025-08-04
sql技巧-每个班年龄排前两名的人2025-08-03
MySQL 导致 cpu 飙升的话,要怎么处理呢?2025-07-29
MySQL 中为千万级大表添加字段2025-07-29
mysql中百万级别以上的数据如何删除2025-07-29
分库分表带来的问题2025-07-29
mysql中常用的分库分表中间件有哪些2025-07-29
mysql不停机扩容2025-07-29
备案号:蜀ICP备2023042032号-1