为何多选择列会使MySQL触发Index Condition Pushdown?性能解析
问题解答:为何第二条SQL触发ICP及性能分析
一、两条SQL的核心差异
第一条SQL查询的last_name和emp_no,刚好能被IDX_LAST_NAME(last_name)这个二级索引完全覆盖——因为InnoDB的二级索引叶子节点会自动包含主键emp_no,数据库直接从索引里就能拿到所有需要的数据,不需要回表,排序也能利用索引本身的有序性(last_name asc, emp_no asc和索引顺序匹配),所以执行计划显示用覆盖索引完成过滤与排序。
第二条SQL多了first_name字段,这个字段不在IDX_LAST_NAME索引里,必须回表到主键索引(聚簇索引)才能获取,这时候就触发了Index Condition Pushdown(ICP)机制。
二、为何第二条SQL会触发ICP?
ICP的核心作用是把WHERE条件的过滤逻辑下推到存储引擎层的索引节点完成,而非先把索引里的主键全拿到Server层再过滤。针对这条SQL:
- 存储引擎会先遍历
IDX_LAST_NAME索引,在索引层面就筛选出last_name IN ('Aamodt','Aaaa','Ab','Ac')的记录,只保留符合条件的主键emp_no; - 再拿着这些主键去聚簇索引回表,取出
first_name等字段。
如果没有ICP,数据库会先把索引里所有主键读取到Server层,再在Server层过滤last_name条件,这会导致大量不必要的回表操作。优化器选择ICP,就是为了减少回表次数,降低整体开销。
三、性能层面的分析
不是仅因回表导致成本更高,要分两部分看:
- 和第一条SQL比,第二条因为必须回表读取聚簇索引数据,总体成本肯定更高——毕竟覆盖索引不需要回表,直接从二级索引就能拿到所有结果,速度更快。
- 但ICP本身是对回表操作的优化:如果符合
last_name条件的记录占比很低,ICP能提前过滤掉大部分不符合条件的索引条目,只对符合条件的记录回表,这比没有ICP时的全量回表再过滤高效得多。
简单说,第二条SQL的成本高是因为需要回表,但ICP是优化手段,用来降低回表带来的额外开销。
内容的提问来源于stack exchange,提问作者Chen Li
相关产品推荐
相关产品推荐

