MySQL 5.7.32中指定SQL为何未使用索引条件下推(ICP)?
问题分析:为何未触发索引条件下推(ICP)
表结构定义
CREATE TABLE `user_cp` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `cp_id` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'cpId 下划线分割', `intimacy` int(11) NOT NULL COMMENT '加了add_exp后的当前等级下的经验', `attenuation_utime` int(11) NOT NULL DEFAULT '0' COMMENT '扣减时间', `utime` int(11) NOT NULL COMMENT '更新时间', `ctime` int(11) NOT NULL COMMENT '时间', PRIMARY KEY (`id`), UNIQUE KEY `cp_id_unique` (`cp_id`), KEY `idx_attenuationutime_utime_intimacy_cpid` (`attenuation_utime`,`utime`,`intimacy`,`cp_id`) ) ENGINE=InnoDB AUTO_INCREMENT=31988443 DEFAULT CHARSET=utf8
查询SQL
EXPLAIN SELECT cp_id FROM user_cp WHERE utime < 1707912100 AND attenuation_utime < 1708430500 AND intimacy > 0
执行环境
MySQL Server版本:5.7.32
未触发ICP的原因分析
原因1:优化器选择全表扫描而非索引扫描
索引条件下推(ICP)仅在使用二级索引扫描时生效。若MySQL优化器评估后认为全表扫描代价更低(例如满足attenuation_utime < 1708430500的行数占表数据量比例极高,索引扫描的IO成本反而高于全表扫描),会直接选择全表扫描,此时ICP自然不会被触发。
原因2:联合索引结构与查询条件的组合限制ICP触发
当前使用的联合索引列顺序为attenuation_utime → utime → intimacy → cp_id,而查询条件存在以下特征:
attenuation_utime < 1708430500是范围条件,作为索引首列,优化器只能扫描所有满足该范围的索引条目;- 后续的
utime < 1707912100和intimacy > 0同样是范围条件,无法利用索引有序性进一步缩小扫描范围。
在MySQL 5.7中,ICP更倾向于触发在前缀列为等值匹配(=、IN),后续列存在过滤条件的场景。当前缀列和后续列均为范围条件时,优化器会认为ICP带来的性能收益有限,因此不启用该优化。
验证建议
- 查看
EXPLAIN结果的type列:若为ALL则是全表扫描,ICP不生效;若为range则是索引范围扫描,需进一步检查Extra列是否包含Using index condition。 - 强制使用目标索引(
FORCE INDEX(idx_attenuationutime_utime_intimacy_cpid))后执行EXPLAIN,观察是否触发ICP。
内容的提问来源于stack exchange,提问作者panici
相关产品推荐
相关产品推荐

