西西软件下载最安全的下载网站、值得信赖的软件下载站!

首页西西教程数据库教程 → 数据库表太大造成的查询效率低下、SQL优化压缩表提高查询效率

数据库表太大造成的查询效率低下、SQL优化压缩表提高查询效率

相关软件相关文章发表评论 来源:西西整理时间:2013/1/7 21:54:19字体大小:A-A+

作者:西西点击:0次评论:0次标签: 数据库

今天收到一个同事的问题,有一段SQL跑了很久很久,根本没有结果,根据同事的反映,这个SQL一个月比一个月要慢。这是不被允许的事情,我们要做的就是对这个SQL进行一次优化。下面就是这次优化的记录。

首先说SQL:

select t.month_id,
       t1.area_id,
       t1.local_id,
       count(distinct case
               when t.type_id = '02' and t.valid_flag = 1 and
                    t3.trade_id = '1008601' then
                t.user_id
               else
                null
             end),
       count(distinct case
               when t.type_id = '02' and t.valid_flag = 1 and
                    t3.trade_id = '1008602' then
                t.user_id
               else
                null
             end)
        from product_flag_m t,
        ... --省略部分都是类似上面的运算,很多,为了节省篇幅都取消了
        left join VW_CODE_LOCALNET t1
          on t.local_id = t1.root_local_id
        LEFT JOIN TRADE_LIST T3
      ON T.id2 = T3.id2
     AND T3.trade_id IN ('1008601', '1008602')
       where t.month_id = '201212'
       group by t.month_id, t1.area_id, t1.local_id;

这段代码隐藏了敏感信息,可能会有一些修改的时候错漏的问题

接下来就是比较老的套路了,查看这段SQL的执行计划:

这个时候可以初步判断是因为product_flag_m表太大造成的查询效率低下。既然只需要12月的数据,那么我自然而然的想到了将12月的分区压缩一下,利用压缩表的特点进行查询效率的提高。但是这是张生产表,不能随便操作,于是我就将12月份的type_id='02'的数据单独抽取出来形成一张新的表,当然这张表是压缩过的,而且我抽取的时候只抽取自己需要的字段,这样做的好处是尽量减少数据量,减轻数据库的负担。

下面就是使用了压缩表之后的执行计划:

可以看到COST是有所降低,但是这个和没有降低没什么区别。还是面临执行不出来的问题。

这个时候我注意到了ID=2的这一部执行计划。在id=3的hash join right outer之后,不管是COST还是BYTES都是在一个比较正常的水平之内的,那么问题就应该出在TRADE_LIST这个表上。

这个表是一张编码,本身并不大,但是注意这里:

上图所示应该就是罪魁了。于是我想到了,既然最后需要过滤一下trade_id,那么为什么不直接就用一张只有trade_id为1008601和1008602的表呢?

于是我鬼使神差的建立了一张视图,这个视图就是只取了上面说的那么多数据,然后替换掉原来的SQL中的TRADE_LIST,删除了其中的

AND T3.trade_id IN ('1008601', '1008602') 语句,再看执行计划:

这个效果就非常好了。

我本身很担心这个视图用了以后会影响查询结果集。于是我自己造了一张表做了一个小测试。test3中有object_id为2, 3, 4, 5, 6, 7的记录,编码表中只有id为2, 3, 4, 5, 6的编码记录,SQL如下:

select t1.object_id, t2.id, t2.name
  from test3 t1
  left join test4 t2
  on t1.object_id = t2.id
  and t2.id in (2, 3);

这个结果有48行。制造一个视图:

create view test5 as select * from test4 where id in (2, 3)

 然后替换成视图:

select t1.object_id, t2.id, t2.name
  from test3 t1
  left join test5 t2
  on t1.object_id = t2.id;

结果还是48行。也就是说这个方法是可行的。

这样的话,如果在原来的SQL上加上并行提示,效果会更好。经过我的实际测试,3分钟以内就跑出了所有的结果。

或许会有人问我,为什么不加上索引?我并不是反对加索引,我不习惯使用索引的习惯是因为我们的现实环境所限,我们的磁盘空间基本上每隔一段时间就会满,所以我没办法随心所欲的添加会占用空间的索引,而是更倾向于使用压缩表,节省表空间。而且,id2字段进行关联的时候有一个隐式类型转换,这个字段起码没有办法加索引。至于其他字段,我没办法实验,如果有机会,可以做个实验试试。

    相关评论

    阅读本文后您有什么感想? 已有人给出评价!

    • 8 喜欢喜欢
    • 3 顶
    • 1 难过难过
    • 5 囧
    • 3 围观围观
    • 2 无聊无聊

    热门评论

    最新评论

    第 1 楼 上海有线通 网友 客人 发表于: 2013/11/5 11:00:52
    居然能重复鄙视。说明程序员做得不到位啊。。。

    支持( 0 ) 盖楼(回复)

    发表评论 查看所有评论(0)

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
    字数: 0/500 (您的评论需要经过审核才能显示)