文档首页
MySQL 9.0 参考手册
相关文档 下载本手册

MySQL 9.0 参考手册  /  ...  /  索引条件下推优化

10.2.1.6 索引条件下推优化

索引条件下推 (ICP) 是一种针对 MySQL 使用索引从表中检索行的情况的优化。如果没有 ICP,存储引擎会遍历索引以在基本表中定位行并将它们返回给 MySQL 服务器,服务器会评估这些行的 WHERE 条件。如果启用了 ICP,并且部分 WHERE 条件可以通过仅使用索引中的列进行评估,则 MySQL 服务器会将此部分 WHERE 条件下推到存储引擎。然后,存储引擎会使用索引条目评估下推的索引条件,只有在满足此条件时才会从表中读取行。ICP 可以减少存储引擎必须访问基本表的次数和 MySQL 服务器必须访问存储引擎的次数。

索引条件下推优化的适用性受以下条件限制

  • 当需要访问完整表行时,ICP 用于 rangerefeq_refref_or_null 访问方法。

  • ICP 可用于 InnoDBMyISAM 表,包括已分区的 InnoDBMyISAM 表。

  • 对于 InnoDB 表,ICP 仅用于二级索引。ICP 的目标是减少完整行读取的次数,从而减少 I/O 操作。对于 InnoDB 聚簇索引,完整记录已读取到 InnoDB 缓冲区中。在这种情况下使用 ICP 不会减少 I/O。

  • 在虚拟生成列上创建的二级索引不支持 ICP。 InnoDB 支持在虚拟生成列上的二级索引。

  • 引用子查询的条件无法下推。

  • 引用存储函数的条件无法下推。存储引擎无法调用存储函数。

  • 触发条件无法下推。(有关触发条件的信息,请参阅 第 10.2.2.3 节,“使用 EXISTS 策略优化子查询”。)

  • 条件无法下推到包含对系统变量的引用的派生表。

要了解这种优化机制的工作原理,首先考虑在不使用索引条件下推的情况下索引扫描如何进行

  1. 获取下一行,首先读取索引元组,然后使用索引元组定位并读取完整表行。

  2. 测试适用于此表的 WHERE 条件的一部分。根据测试结果接受或拒绝该行。

使用索引条件下推,扫描会改为如下进行

  1. 获取下一行的索引元组(但不获取完整表行)。

  2. 测试适用于此表并且可以使用仅索引列进行检查的 WHERE 条件的一部分。如果条件不满足,则继续进行到下一行的索引元组。

  3. 如果条件满足,则使用索引元组定位并读取完整表行。

  4. 测试适用于此表的 WHERE 条件的剩余部分。根据测试结果接受或拒绝该行。

EXPLAIN 输出在 Extra 列中显示 Using index condition,如果使用了索引条件下推。它不会显示 Using index,因为这在必须读取完整表行时不适用。

假设一个表包含有关人员及其地址的信息,并且该表有一个定义为 INDEX (zipcode, lastname, firstname) 的索引。如果我们知道一个人的 zipcode 值,但不确定姓氏,我们可以像这样搜索

SELECT * FROM people
  WHERE zipcode='95054'
  AND lastname LIKE '%etrunia%'
  AND address LIKE '%Main Street%';

MySQL 可以使用索引扫描具有 zipcode='95054' 的人员。第二部分 (lastname LIKE '%etrunia%') 无法用于限制必须扫描的行数,因此在没有索引条件下推的情况下,此查询必须检索所有具有 zipcode='95054' 的人员的完整表行。

在索引条件下推的情况下,MySQL 会在读取完整表行之前检查 lastname LIKE '%etrunia%' 部分。这避免了读取与 zipcode 条件匹配但与 lastname 条件不匹配的索引元组对应的完整行。

索引条件下推默认启用。可以通过设置 optimizer_switch 系统变量的 index_condition_pushdown 标志来控制它。

SET optimizer_switch = 'index_condition_pushdown=off';
SET optimizer_switch = 'index_condition_pushdown=on';

请参见 第 10.9.2 节,“可切换优化”