慢SQL治理案例

本文介绍了优化SQL查询的五个关键策略:避免全表扫描,合理设计索引,减少不必要的排序,精细化查询条件,以及解决OR引起的索引失效问题。通过案例分析和解决方案,展示了如何提升数据库性能,降低慢查询的出现。
摘要由CSDN通过智能技术生成

一、全表扫描

扫描全表治理简单来说就是加入查询条件,命中索引,去除全表扫描查询,虽然有些粗暴,但并不是没有道理。实际业务场景中,很少有要扫描全表获取全部数据的情况,限制调用上游必须传入查询条件,且该查询条件能命中索引,能很大程度上避免慢sql。
数据表的设计使用,明确表的使用规范,不乱写入数据,能给后期维护带来很大的便利,保持表数据的clean。

二、索引混乱

  1. 例子
    在这里插入图片描述
    2.分析
    除了时间、操作人字段,XXX_rules表就rule_name、rule_value、status、product_code四个字段,表的索引对这四个字段做各种排列组合。存在如下问题:
    1)rule_name离散度不高,放在索引首位不合适;
    2)前三个索引重合度很高;
    显然是对索引的命中规则不够了解。XXX_rules表很多业务有定时任务对其写入删除,索引多、混乱,对性能有很大的影响。
    高性能索引有哪些
    ①独立的列:索引列不能是表达式的一部分;
    ②选择区分度高的列作为索引;
    ③选择合适的索引列顺序:将选择性高的索引列放在最前列;
    ④覆盖索引:查询的列均在索引中,不需要回查聚簇索引;
    ⑤使用索引扫描来做排序;
    ⑥在遵守最左前缀的原则下,尽量扩展索引,而不是创建索引。
    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_report
WHERE 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,即扫描全表?索引失效了?索引失效有哪些情况?

索引失效场景:
①OR查询左右有未命中索引的;
②复合索引不满足最左匹配原则;
③Like以%开头;
④需要类型转换;
⑤where中索引列有运算;
⑥where中索引列使用了函数;
⑦如果mysql觉得全表扫描更快时(数据少时)
上述查询语句第8行,customer_id为XXX_level_report表字段,未命中XXX_white_list表索引,导致索引失效。

3.解决方案
这个语句用condition、枚举、join花里胡哨的代码拼接起来的,改起来好麻烦,而且看起来“OR customer_id LIKE CONCAT(t.biz_id, ‘@%’)”这句不能直接删掉。最后重构了该部分的查询语句,去除or查询,解决了慢sql。

文章来自阿里慢SQL治理5大经典案例

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值