记一次生产SQL强势优化
Posted xiangerfer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次生产SQL强势优化相关的知识,希望对你有一定的参考价值。
受同事dd之托,优化一条boss看的报表SQL。dd写复杂疑难SQL无数,如何写出优雅的SQL自有一番心得体会。能将一条7表含inner join,left join并含有关联子查询的、返回结果集3400余条的SQL优化到2s已足以证明功力之深厚。此次也是在她的基础上加以分析,优化,将此过程记录分享。
1、原始SQL。希望将执行时间缩减到1s以内。
执行计划如下:(执行时间2.063 sec)
?
摘除红框的where条件执行计划如下:(执行时间0.452 sec)
分析:SQL中的where条件为不相关子查询。然后使用not in
分析1:
not in 在这里形成了笛卡尔积。形成3418*252次判断。如果改成in则会走索引。执行时间0.2s
于是灵光一现。想到:
不加where条件返回的数据集 - in 返回的数据集 = 原SQL中返回的数据集。
两个执行时间为0.2s 的SQL相减 得到执行时间为 0 。真diao!
分析2:
冥冥之中自由一股力量引领我将where条件中的表和大表做条件关联。
以避免这种毫无关系的笛卡尔积,同时也实现了江湖人人歌颂的小结果集驱动(红框中STRAIGHT_JOIN强制指定驱动表顺序)。
于是乎另一种写法闪亮登场。执行时间:0.248 sec . 真屌!
备注(废话):正常来说,在一个结果集后面加where条件不会比没有where条件时糟糕。理由如下:
第一种情况:如果该where条件列有索引
1、使用到了索引。
1、为减少CPU的使用而走的索引。比如对结果集进行排序(分组),最值等。
2、为减少IO而走的索引。
如果CPU强劲(频率高),排序计算的时间就很快。
如果IO吞吐能力强(假设产生物理读),CPU处于IO wait的时间就相对少。即便这样关系型数据库中也不建议产生大量的物理读。一来,外存的IO速度与CPU处理之间有不可逾越的鸿沟,同时,同时也防止大量的读将
内存池数据(buffer pool data)被swap out出去。
总结就是:
待取的数据/实际读出的数据 约接近1越好。体现在执行计划列rows的值接近实际返回的行数(found_rows())。
当然最好的设计模式是1、2兼得。最典型的案例如索引(column1,column2)
where column1 = ‘value1’ [group|order] by column2类似查询。
2、没有使用到索引。
1、确实不可走。如联合索引的后缀。这由B+Tree索引的数据结构决定。等
2、优化器认为走索引的代价不如不走索引。通过非聚集索引(也称为二级索引)的指针找表的过程俗称回表(同样有不回表的覆盖索引(Extra列含有use index))。大量的回表不如全表扫。这是大多数能走的索引却
不走的原因。这个过程基于数据库内部维护对表的定期采样的数据。统计信息的不准也会导致该走某个索引却没有走。等
如果有索引却没有使用到索引,获取到结果集的时间理论上是略大于没有where条件的。(优化器发现该表有可用的索引,会分析走索引的代价,略微增加了解析时间,除非关联的表异常多,一般可忽略不计)。
多数情况我们信任基于成本(CBO)查询优化器(Query Optimizer)。如果不,也可以通过IGNORE,FORCE,USE忽略、强制、建议走索引。
第二种情况:如果没有索引
1. 多了判断是否符合where条件的计算的时间。甚至如果此时CPU使用率异常繁忙,可能会
因为抢占不到CPU时间导致一条简单的SQL 语句hang住。
所以如果没有索引 ,有where条件获取到结果集的时间大于没有where条件。(如果远程客户端,假定网络带宽足够大)
ps:如上备注,均为个人见解。如有不当,还望交流指点。qq:475982055
以上是关于记一次生产SQL强势优化的主要内容,如果未能解决你的问题,请参考以下文章