前言
说到MySQL的优化手段,不得不提的是MYSQL5.6中引入的一种新特性,索引下推,英文是indexconditionpushdown,一般简称为ICP。这也是MySQL面试中经常被问到的一个考点,本文就此分享下索引下推是怎么一回事,它是如何对提高查询效率起到帮助的。
理解索引下推
索引下推就是指在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数来提高查询效率。
如何理解呢?我们直接上栗子来解释:
新建用户表
CREATETABLEuser(`id`intNOTNULLAUTO_INCREMENT,`zipcode`varchar(20)DEFAULTNULL,`name`varchar(20)DEFAULTNULL,`addss`varchar(50)DEFAULTNULL,PRIMARYKEY(`id`),indexidx_zip_name(`zipcode`,`name`))ENGINE=INNODB;insertintouser(zipcode,name,addss)values(,陈旭阳,杭州),(,胡歌,上海),(,杨幂,北京),(,刘诗诗,南京);
创建了基于邮编zipcode和名称name的联合索引idx_zip_name,用于查找某个邮编下,名字包含陈的人。
查询语句
select*fromuserwhezipcode=andnamelike%陈%andaddsslike%余杭%;
查询条件根据zipcode精确查找,name和addss全模糊匹配。
如果MySQL5.6以前,没有索引下推特性,整个流程如下图:
联合索引中知道的数据项,因为name是全模糊,无法走索引,addss压根没有索引,他们无法在联合索引中过滤,怎么办?只能回到数据最全的聚簇索引上进行namelike%陈%andaddsslike%余杭%这个逻辑的过滤。
按照上面的方式,每次回到聚簇索引这个一个称做“回表”的过程,势必增加磁盘IO,从而影响查询性能。
那么有什么办法可以优化呢?
优化的目标就是尽量减少回表这一过程,我们发现联合索引上竟然有了name字段的信息,为什么我们不能充分利用呢?namelike%陈%我们可以直接在索引树上进行判断name是不是包含陈,从而减少回表次数。这也正是MySQL5.6中优化的特性,如下图所示:
根据查询条件namelike%陈%,陈旭阳包含了陈,那么它去回表过滤addss内容。
而其他记录比如胡歌等不包含陈,那么其他记录就无需回表,再次去匹配addss地址是否符合了,相当于减少了回表。
上面图中的索引都用表格表示,只是为了方便,实际上索引底层数据结构是B+数据,如果不了解的,可以阅读文章:一步步带你设计MySQL索引数据结构
一句话总结:索引下推(indexconditionpushdown,ICP),有效的减少了回表次数,提高了查询效率。
索引下推性能比较
竟然索引下推可以提高效率,那我们验证下。
沿用上面的user表
创建存储过程,添加数据
DELIMITER//CREATEPROCEDUREinsert_user(max_numINT)BEGINDECLAREiINTDEFAULT0;SETauto