日期:2014-05-16  浏览次数:20419 次

一次优化记录

    今天收到一个同事的求助,说有一个SQL跑了一个多小时没有结果。我看了看,这个SQL是这样的(隐藏了敏感信息):

    

SELECT 电话号码, 列2, 列3, MAX(STARTTIME), FLAG
  FROM 表1 T1
 WHERE FLAG = '0'
   AND 电话号码 NOT IN (SELECT 电话号码 FROM 表2 T2)
 GROUP BY 电话号码, 列2, 列3, FLAG;

     我首先查看了两个表的数据量,表1有将近300万条,表2有不到10万条记录。并不是很大的数据。于是我关注到了not in,这个语句是几乎所有的优化指南上都明确说了要避免的语句。于是我就把这句改了,改成了not exists:

    

复制代码
SELECT 电话号码, 列2, 列3, MAX(STARTTIME), FLAG
  FROM 表1_新 T1
 WHERE FLAG = '0'
   AND NOT EXISTS
 (SELECT 电话号码 FROM 表2 T2 WHERE T1.电话号码 = T2.电话号码)
 GROUP BY 电话号码, 列2, 列3, FLAG;
复制代码

 

     但是COST仅仅降低到了原来的五分之一,这远远不是我需要的。我需要的是质一样的飞跃。

     我看了一下原本SQL的执行计划:

     

       我发现全表扫描耗用很大。查询一下数据,发现这是一张客户信息表,所有人的电话号码都是不同的,因此我想到了将这个表改成一个哈希分区表。至于为什么会想到哈希分区表,参考我以前写过的:http://www.cnblogs.com/wingsless/archive/2012/09/28/2707661.html。

       我建立了一张哈希分区表:表1_新。

       这个时候我用刚才改的语句,然后看看执行计划:

       

      这个效果就非常好了,36847的COST和2684K的COST比起来简直是天壤之别。实际测试一下,查询出所有的数据仅仅需要55秒。

      如果不用not exists,在哈希分区表上用原来的SQL查查,执行计划是这样的:

      

      可以看到COST会有下降,但是仅仅是一半左右,这也不是优化所要达到的目的。

      其实这次SQL优化的主要在于使用了not exists。因为在三个执行计划中,最开始的对表1或者表1_新的扫描,COST都不到20000,而且很接近,因此哈希分区应该并不是提升效率的关键。至于效率为什么提高,这句是关键:access("T1"."电话号码"="T2"."电话号码")。关于not in和not exists的优劣区别,今天太晚了,周末再好好写写吧。 

      有几次同事问我怎么去优化?其实优化,我觉得并没有什么技巧,应该就和踢足球一样,没有什么战无不胜的踢法,只有对场上局面冷静的分析,随时调整战法,才能无往而不利,这样才是好的教练,这应该就是穆里尼奥的本事。优化也是这样的,不同的SQL有不同的优化方法,冷静的分析,运用自己学过的技术,总能把调优做的很好。