专题名称范围查询如何使用复合索引的专题报告

专题描述解决含有范围查询的SQL语句where条件中若不强制使用索引,只有部分列使用到索引的问题。

问题提出

1、分配承运商性能测试时发现SQL出现执行计划走偏的情况,只能通过强制指定索引才生效,强制指定索引1秒多,不强制指定索引要花58秒(性能测试库10.202.198.200),SQL如下:
select * from wom_tb_order_header force index (idx_tb_order_header_test7) where process_tm > '2015-06-15 14:27:19' and process_status =2 and process_job_num ='AC_10.202.26.38080'

分析过程

1、从给出的SQL语句分析,在不强制使用索引的情况下,执行缓慢的原因是:该SQL语句使用的是全表扫描方式。

强制使用索引之后,该SQL走idx_tb_order_header_test7(process_tm,process_status)索引。之所以走不上索引的原因因为优化器是基于成本来决定是否选择索引和具体索引选择项。

该索引第一列为process_tm在原SQL语句中为一个范围查询,那么idx_tb_order_header_test7(process_tm,process_status)索引只能使用到第一列process_tm,而第二列process_status是不能走上索引的。

解决方案

1、将idx_tb_order_header_test7索引修改为(process_status,process_tm)。
不建议使用force index,因为如果删除该索引,将导致该语句执行报错。

问题原因

1、没有使用index condition pushdown时,SQL语句中where子句中范围查询之后的列无法使用联合索引。

知识点

1、ICP(index condition pushdown)是mysql利用索引(二级索引)元组和筛字段在索引中的where条件从表中提取数据记录的一种优化操作。ICP的思想是:存储引擎在访问索引的时候检查筛选字段在索引中的where条件(pushed index condition,推送的索引条件),如果索引元组中的数据不满足推送的索引条件,那么就过滤掉该条数据记录。ICP(优化器)尽可能的把index condition的处理从server层下推到storage engine层。storage engine使用索引过过滤不相关的数据,仅返回符合index condition条件的数据给server层。也是说数据过滤尽可能在storage engine层进行,而不是返回所有数据给server层,然后后再根据where条件进行过滤。

MySQL5.6可以通过设置optimizer_switch([global|session],dynamic)变量开启或者关闭index_condition_push优化功能,默认开启。
mysql > set optimizer_switch=’index_condition_pushdown=on|off’

explain查看执行计划时,如果执行计划中的Extra信息为“using index condition”,表示优化器使用的index condition pushdown。
mysql5.6以前,还没有采用ICP这种查询优化,where查询条件中的索引条件在某些情况下没有充分利用索引过滤数据。假设一个组合索引(多列索引)K包含(c1,c2,…,cn)n个列,如果在c1上存在范围扫描的where条件,那么剩余的c2,…,cn这n-1个上索引都无法用来提取和过滤数据(不管不管是唯一查找还是范围查找),索引记录没有被充分利用。即组合索引前面字段上存在范围查询,那么后面的部分的索引将不能被使用,因为后面部分的索引数据是无序。比如,索引key(a,b)中的元组数据为(0,100)、(1,50)、(1,100) ,where查询条件为 a < 2 and b = 100。由于b上得索引数据并不是连续区间,因为在读取(1,50)之后不再会读取(1,100),mysql优化器在执行索引区间扫描之后也不再扫描组合索引其后面的部分。