|慢sql治理经典案例分享( 二 )


3、选择合适的索引列顺序:将选择性高的索引列放在最前列;
4、覆盖索引:查询的列均在索引中 , 不需要回查聚簇索引;
5、使用索引扫描来做排序;
6、在遵守最左前缀的原则下 , 尽量扩展索引 , 而不是创建索引 。
但凡记得第3和6规则 , 也不至于把索引建成这样 。
3 治理
对索引进行整合如下:

系统中有很多任务拉取整个产品下的准入记录 , 然后进行处理 , 所以将区分度较高的product_code放在索引首位 , 然后添加rule_name、status字段到索引里 , 进一步过滤数据 , 减少扫描行数 , 避免慢sql 。 针对常用的rule_value查询条件 , 可以命中UK , 因此不用单独建立索引 。
三 非必要排序 1 问题描述
很多业务逻辑中 , 需要拉取满足某个条件的记录列表 , 查询的sql语句带有order by , 记录比较多的情况 , 排序代价往往很大 , 但是查询出来的记录是否有序对业务逻辑没有影响 , 比如分页治理里讨论的count语句 , 只需要统计条数 , order by对条数没有影响 , 再比如查出记录列表后 , 不依赖记录的顺序遍历列表处理数据 , 这时候order by多此一举 。
2 解决方案
查询sql无limit语句 , 且业务处理逻辑不依赖于order by后列表记录的顺序 , 则去除查询sql中的order by语句 。
四 粗粒度查询 1 问题描述
业务中有很多定时任务 , 扫描某个表中某个产品下所有数据 , 对数据进行处理 , 比如:
SELECT * FROM XXX_rules WHERE rule_name = 'apf_distributors' AND status = '00' AND product_code = 'ADVANCE' 三个查询条件都是区分度不高的列 , 查出的数据有27W条 , 加索引意义也不大 。
2 分析
实际业务量没那么大 , 顶多几千条数据 , 表里的数据是从上游同步过来的 , 最好的办法是让上游精简数据 , 但是由于业务太久远 , 找上游的人维护难度太大 , 因此只能想其他的办法 。
这个定时任务目的是拉出XXX_rules表的某些产品下的数据 , 和另一张表数据对比 , 更新有差异的数据 。 每天凌晨处理 , 对时效性没有很高的要求 , 因此 , 能不能转移任务处理的地方 , 不在本应用机器上实时处理那么多条数据?
3 解决方案
数据是离线任务odps同步过来的 , 首先想到的就是dataWork数据处理平台 。
建立数据对比任务 , 将定时任务做的数据对比逻辑放到dataWork上用sql实现 , 每天差异数据最多几百条 , 且结果集含有区分度很高的列 , 将差异数据写入odps表 , 再将数据回流到idb 。
新建定时任务 , 通过回流回来的差异数据中区分度高的列作为查询条件查询XXX_rules , 更新XXX_rules , 解决了慢sql问题 。
这个方法的前提是对数据实效性要求不高 , 且离线产出的结果集很小 。
五 OR导致索引失效 1 案例
SELECT count(*)FROM XXX_level_reportWHERE 1 = 1 AND EXISTS ( SELECT 1 FROM XXX_white_list t WHERE (t.biz_id = customer_id OR customer_id LIKE CONCAT(t.biz_id '@%')) AND t.status = 1 AND (t.start_time= CURRENT_TIME OR t.start_time IS NULL) AND (t.end_time= CURRENT_TIME OR t.end_time IS NULL) AND t.biz_type = 'GOODS_CONTROL_BLACKLIST' ) 2 分析
explain上述查询语句 , 得到结果如下:

XXX_white_list表有将biz_id作为索引 , 这里查询XXX_white_list表有传入biz_id作为查询条件 , 为啥explain结果里type为ALL , 即扫描全表?索引失效了?索引失效有哪些情况?
索引失效场景
1、OR查询左右有未命中索引的;
2、复合索引不满足最左匹配原则;
3、Like以%开头;
4、需要类型转换;
5、where中索引列有运算;