索引下推优化
Index Condition Pushdown(ICP)是对 MySQL 使用索引从表中检索行的情况的优化。
如果没有 ICP,存储引擎会遍历索引以查找基表中的行,并将它们返回给 MySQL 服务层,该服务层会过滤 WHERE 行的条件。
启用 ICP 后,如果 WHERE 只使用索引中的列来过滤部分条件,MySQL 服务层会推送这部分内容。WHERE 条件下推到存储引擎。然后,存储引擎使用索引条目过滤推送的索引条件,并且仅当满足该条件时才从表中读取行。
ICP 可以减少存储引擎必须访问基表的次数以及 MySQL 服务层必须访问存储引擎的次数。
条件限制
- ICP 用于 range, ref, eq_ref,和 ref_or_null 访问方法时,有必要访问完整的表行。
- ICP 可用于表 InnoDB 和 MyISAM 表,包括分区 InnoDB 和 MyISAM 表。
- 对于 InnoDB 表,ICP 仅用于二级索引。ICP 的目标是减少全行读取的数量,从而减少 I/O操作。对于 InnoDB 聚簇索引,已将完整记录读入 InnoDB 缓冲区。在这种情况下使用 ICP 不会降低 I/O。
- 在虚拟生成列上创建的二级索引不支持 ICP。InnoDB 支持虚拟生成列上的二级索引。
- 引用子查询的条件无法下推。
- 无法下推涉及存储函数的条件。存储引擎无法调用存储的函数。
- 触发条件无法下推。
没有使用索引下推的工作原理
- 获取下一行,首先读取索引元组,然后使用索引元组找到并读取整个表行。
测试 WHERE 适用于此表的条件部分。根据测试结果接受或拒绝该行。
使用索引下推的工作原理
获取下一行的索引元组(但不是完整的表行)。
- 测试 WHERE 适用于此表的条件部分,并且只能使用索引列进行检查。如果不满足条件,则继续下一行的索引元组。
- 如果满足条件,请使用索引元组来查找并读取整个表行。
- 测试 WHERE 适用于此表的条件的剩余部分。根据测试结果接受或拒绝该行。
测试
建表语句:
上表创建表的时候生成了一个联合索引DROP TABLE IF EXISTS `person`;CREATE TABLE `person` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`zipcode` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`lastname` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',`address` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',`firstname` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',PRIMARY KEY (`id`) USING BTREE,INDEX `idx_zipcode`(`zipcode`, `lastname`, `firstname`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
idx_zipcode。
开启索引下推:
生成执行计划:set optimizer_switch='index_condition_pushdown=on';
执行计划:EXPLAIN SELECT * FROM person WHERE zipcode='95054' AND lastname LIKE '%etrunia%' AND address LIKE '%Main Street%';
关闭索引下推:
执行计划:set optimizer_switch='index_condition_pushdown=off';
参考资料
Index Condition Pushdown Optimization
