0

0

索引下推(Index Condition Pushdown)优化是什么?

betcha

betcha

发布时间:2025-09-09 12:00:04

|

1076人浏览过

|

来源于php中文网

原创

索引下推通过将WHERE条件中涉及索引列的过滤下推到存储引擎层执行,减少回表和数据传输量,从而提升查询性能。具体表现为:在复合索引查询中,存储引擎利用索引条目直接过滤非前缀列条件(如WHERE city='New York' AND age>30),仅将满足所有索引条件的行回表并传给服务器层,避免了大量无效数据的传输与处理。该优化适用于复合索引的非前缀列、LIKE前缀匹配、ENUM列等场景,但要求条件列必须包含在索引中且不使用函数或表达式。从MySQL 5.6开始支持,通过EXPLAIN执行计划中Extra列是否出现“Using index condition”可判断其是否生效。

索引下推(index condition pushdown)优化是什么?

索引下推(Index Condition Pushdown,简称ICP)优化,说白了,就是数据库在处理查询时,把一部分原本要在服务器层(Server Layer)做的条件过滤,提前下放到存储引擎层(Storage Engine Layer)去执行。这样一来,存储引擎就只把那些真正符合条件的行传给服务器层,大大减少了数据传输量,自然也就提升了查询效率。

解决方案

理解索引下推,得先知道MySQL大致分两层:服务器层和存储引擎层。服务器层负责SQL解析、查询优化、缓存、日志等,而存储引擎层(比如InnoDB)则负责实际的数据存储和检索。

在没有ICP的情况下,如果一个查询使用了复合索引,但

WHERE
子句中除了用于索引查找的列,还有索引中其他列的条件,那么存储引擎会先根据索引查找定位到所有符合索引查找条件的行(比如
idx_city_age
索引中的
city = 'New York'
),然后把这些行的所有数据(或者至少是请求的列)都加载到服务器层。服务器层再对这些数据进行二次过滤(比如
age > 30
)。

而有了ICP,如果

WHERE
子句中的某些条件只涉及到索引列,即使这些列不是索引的“前缀”部分,存储引擎也可以在读取索引条目时就对这些条件进行判断。它会利用索引中的信息,直接过滤掉不符合条件的行,只把那些既满足索引查找条件又满足下推条件的行传给服务器层。

举个例子,你有一个复合索引

(city, age)
,查询是
SELECT * FROM users WHERE city = 'New York' AND age > 30;

  • 没有ICP: 存储引擎找到所有
    city = 'New York'
    的索引条目,然后回表(如果不是覆盖索引)获取完整行数据,将这些行全部发送给服务器层。服务器层再逐行判断
    age > 30
  • 有ICP: 存储引擎在遍历
    city = 'New York'
    的索引条目时,会同时检查
    age > 30
    这个条件。只有当
    city = 'New York'
    age > 30
    都满足时,才去回表获取完整行数据,并将这些行发送给服务器层。这样,存储引擎和服务器层之间的数据传输量就显著减少了。

在我看来,ICP最直观的价值就是减少了“无用功”。那些明明可以在数据源头就过滤掉的数据,就不必千里迢迢地传输到上层再被抛弃,这对于IO密集型的数据库操作来说,简直是雪中送炭。

索引下推是如何提升查询性能的?

说起来,性能提升主要体现在两个方面:数据传输量和CPU消耗。

首先是减少数据传输量。想象一下,如果你的索引覆盖了查询所需的所有列,并且

WHERE
条件中包含了这些索引列,那么在没有ICP时,存储引擎会根据索引找到所有符合主查询条件的索引条目,然后把这些条目对应的“完整”行数据(或者说,至少是那些需要进一步过滤的行)都一股脑地丢给服务器层。但如果有了ICP,存储引擎在扫描索引的时候,就能提前利用索引中的信息把不符合下推条件的行给筛掉。这意味着,从存储引擎到服务器层的数据通道上,流过的都是“精挑细选”过的有效数据,而不是一大堆可能很快就会被抛弃的“垃圾”。数据量少了,传输自然就快,尤其是当表很大,符合初步索引条件的行很多,但符合下推条件的行很少时,这个效果尤为显著。

其次是降低CPU消耗。数据传输量的减少,直接导致服务器层需要处理的行数变少。这意味着服务器层在进行最终过滤、排序、聚合等操作时,CPU的负担会轻很多。毕竟,处理几百行数据和处理几万行数据,CPU的忙碌程度是完全不同的。而且,原本在服务器层进行的条件判断,现在下放到存储引擎层,存储引擎往往对数据结构有更深入的了解,理论上可以更高效地进行这些判断。

举个例子,我们有张表

employees
,上面有一个复合索引
(department_id, salary, hire_date)
。 如果我们执行查询:
SELECT * FROM employees WHERE department_id = 10 AND salary > 50000 AND hire_date < '2020-01-01';
在ICP的加持下:

  1. 存储引擎会先用
    department_id = 10
    进行索引定位。
  2. 在遍历
    department_id = 10
    的索引条目时,它会利用索引中的
    salary
    hire_date
    信息,直接判断
    salary > 50000
    hire_date < '2020-01-01'
  3. 只有当这三个条件都满足时,存储引擎才会去读取完整的行数据,并将其传给服务器层。

这就像快递员送包裹,以前是把所有目的地在某个区域的包裹都送到分拣中心,分拣中心再根据具体门牌号筛选。现在是快递员在揽件的时候就根据门牌号把不符合的包裹筛选掉了,分拣中心收到的就是可以直接派送的包裹,效率自然高了。

哪些场景下索引下推会生效?

索引下推并不是万能的,它有自己的适用范围和条件。主要是在以下几种场景下会发挥作用:

  1. 复合索引的非前缀列条件: 这是最典型的应用场景。当你的

    WHERE
    子句中,除了用于索引查找(比如
    range
    ref
    类型)的索引前缀列外,还包含了该复合索引中其他非前缀列的条件时,ICP就能介入。

    • 例如:索引
      (col1, col2, col3)
      ,查询
      WHERE col1 = 'A' AND col3 > 10
      col1 = 'A'
      用于索引定位,
      col3 > 10
      就是可以被下推的条件。
  2. LIKE
    操作符:
    LIKE
    模式不是以通配符开头,并且可以利用索引前缀进行范围扫描时,
    LIKE
    条件中剩余的部分(如果仍然是索引列的一部分)就有可能被下推。

    • 例如:索引
      (name)
      ,查询
      WHERE name LIKE 'John%' AND name LIKE '%son'
      'John%'
      用于索引范围扫描,而
      '%son'
      这个条件,如果能在索引条目上直接判断,也会被下推。不过,这种情况相对复杂,更常见的是
      LIKE 'prefix%'
      本身作为索引扫描条件。
  3. 多列索引中的

    OR
    条件(有限制): 虽然
    OR
    条件通常会阻碍索引使用,但在某些特定情况下,如果
    OR
    连接的条件都只涉及索引列,并且优化器认为下推有利,也可能发生。但这不如
    AND
    条件常见和有效。

    sematic
    sematic

    一个开源的机器学习平台

    下载
  4. ENUM
    类型列的条件: 如果索引列是
    ENUM
    类型,并且
    WHERE
    条件中对
    ENUM
    值进行了过滤,ICP也能很好地工作。

限制和不生效的场景:

  • 非索引列条件: 如果
    WHERE
    条件中包含的列不在索引中,那么这个条件就无法被下推。存储引擎无法访问这些列的信息。
  • 函数或表达式: 如果
    WHERE
    条件中对索引列使用了函数或表达式(例如
    WHERE YEAR(hire_date) = 2020
    ),通常也无法下推,因为存储引擎需要先计算函数结果才能判断,这超出了它直接处理索引条目的能力。
  • NOT EXISTS
    NOT IN
    子查询:
    这些复杂查询的优化器行为比较特殊,ICP通常不适用。
  • 全文索引和空间索引: ICP主要针对B-tree索引。
  • MySQL版本: 索引下推是MySQL 5.6版本引入的特性,如果你还在用更老的版本,那自然是享受不到这项优化了。

理解这些适用场景,能帮助我们更好地设计索引和编写查询语句,让数据库的优化器有更多“施展拳脚”的空间。

如何判断我的查询是否使用了索引下推?

要判断一个查询是否用到了索引下推,最直接、最权威的工具就是MySQL的

EXPLAIN
语句。当你运行
EXPLAIN
来分析你的SQL查询时,你需要关注结果中的
Extra
列。

如果

Extra
列中出现了
Using index condition
,那么恭喜你,你的查询就利用了索引下推优化。

我们来看一个具体的例子:

假设我们有一个用户表

user_profiles
,包含
id
,
first_name
,
last_name
,
age
,
city
等字段。我们为
city
age
建立了一个复合索引:

CREATE TABLE user_profiles (
    id INT PRIMARY KEY AUTO_INCREMENT,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    age INT,
    city VARCHAR(50),
    INDEX idx_city_age (city, age)
);

INSERT INTO user_profiles (first_name, last_name, age, city) VALUES
('Alice', 'Smith', 30, 'New York'),
('Bob', 'Johnson', 25, 'London'),
('Charlie', 'Brown', 35, 'New York'),
('David', 'Miller', 40, 'Paris'),
('Eve', 'Davis', 28, 'London'),
('Frank', 'Wilson', 32, 'New York'),
('Grace', 'Moore', 27, 'London');

现在,我们执行一个查询,并用

EXPLAIN
分析:

EXPLAIN SELECT * FROM user_profiles WHERE city = 'New York' AND age > 30;

你可能会看到类似这样的输出(具体内容可能因MySQL版本和数据分布略有差异):

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE user_profiles NULL ref idx_city_age idx_city_age 203 const 3 33.33 Using index condition

在上面的

EXPLAIN
结果中,
Extra
列显示了
Using index condition
。这明确告诉我们,优化器决定使用索引下推来处理
age > 30
这个条件。具体来说,存储引擎在扫描
idx_city_age
索引,找到所有
city = 'New York'
的条目时,会同时检查这些条目中的
age
值是否大于 30。只有那些同时满足
city = 'New York'
age > 30
的索引条目,才会触发回表操作(因为我们查询的是
SELECT *
),将完整的行数据传给服务器层。

如果没有

Using index condition
,而是显示
Using where; Using index
或者仅仅是
Using where
,那么就意味着虽然可能使用了索引,但
WHERE
子句的过滤是在服务器层完成的,没有利用到索引下推的优势。

掌握

EXPLAIN
是数据库性能优化的基础,通过它,我们不仅能判断ICP是否生效,还能深入了解查询的执行计划,从而做出更精准的优化决策。它就像是数据库的“X光片”,能让你看到内部的运行机制。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

674

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

319

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

345

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1084

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

355

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

671

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

566

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

408

2024.04.29

vlookup函数使用大全
vlookup函数使用大全

本专题整合了vlookup函数相关 教程,阅读专题下面的文章了解更多详细内容。

28

2025.12.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 1.5万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 777人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号