Mysql的索引条件下推是怎么回事?有什么用?理论篇

Mysql的索引条件下推优化

前言

本文是从官方文档英文版翻译过来,文末附上了官网地址

正文

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

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

  • 当需要访问整个表行时 , ICP 用于 rangerefeq_ref和 访问方法。ref_or_null
  • ICP可以用于InnoDB andMyISAM表,包括分区表InnoDBMyISAM表。
  • 对于InnoDB表,ICP 仅用于二级索引。ICP 的目标是减少全行读取次数,从而减少 I/O 操作。对于 InnoDB聚集索引,完整的记录已经读入InnoDB 缓冲区。在这种情况下使用 ICP 不会减少 I/O。
  • 在虚拟生成列上创建的二级索引不支持 ICP。InnoDB 支持虚拟生成列的二级索引。
  • 引用子查询的条件不能下推。
  • 引用存储功能的条件不能下推。存储引擎不能调用存储的函数。
  • 触发条件不能下推。(有关触发条件的信息,请参阅 “使用 EXISTS 策略优化子查询”。)

要了解这种优化是如何工作的,首先要考虑在不使用索引条件下推时索引扫描是如何进行的:

  1. 获取下一行,首先通过读取索引元组,然后使用索引元组定位并读取全表行。
  2. 在该表上测试部分WHERE条件。根据测试结果接受或拒绝该行。

使用索引条件下推,扫描会像这样进行:

  1. 获取下一行的索引元组(但不是整个表行)。
  2. 在该表上测试部分WHERE条件,并且只能使用索引列进行检查。如果条件不满足,则继续下一行的索引元组。
  3. 如果满足条件,则使用索引元组定位并读取全表行。
  4. 在该表上测试其余部分的WHERE条件。根据测试结果接受或拒绝该行。

当使用索引条件下推时,在EXPLAINExtra列中输出显示成 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 条件的索引元组对应的完整行。

默认情况下是开启索引条件下推优化的。可以通过设置 index_condition_pushdown 标志来控制 optimizer_switch系统变量。

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

参考:
MySQL 参考手册 - 索引条件下推优化

猜你喜欢

转载自blog.csdn.net/booynal/article/details/125667378