执行长达2分多钟的大型sql优化

在工作中,有些报表的展示较复杂,且需要统计的内容不断变化,开发的sql越来越长,运行越来越慢,这时优化必不可免,先来看下如下冗长的执行了2分多钟的sql,看看从中是否能找出些规律
SELECT  T1.BASE_YW
                ,T1.BRNC_ID
                ,T1.OFFC_ID
                ,T1.MKT_MODL_ID
                ,T1.BASC_MODL
                ,T1.BI_CHNL_TP_02
                ,T1.BI_CHNL_TP_03
                ,T1.BRNC_ID_NM
                ,T1.OFFC_ID_NM
                ,T1.MKT_MODL_DI_NM
                ,T1.BASC_MODL_NM
                ,T1.BI_CHNL_TP_02_NM
                ,T1.BI_CHNL_TP_03_NM
                ,T2.SHOP_CNT
                ,T1.YW_01_SHOP_CNT
                ,T1.YW_02_SHOP_CNT
                ,T1.YW_03_SHOP_CNT
                ,T1.YW_04_SHOP_CNT
                ,T1.YW_05_SHOP_CNT
                ,T1.YW_06_SHOP_CNT
               
                ,0 GR_BI_CHNL_TP_02
                ,0 GR_BI_CHNL_TP_03
                ,0 GR_MKT_MODL_ID --ADD
                ,0 GR_BASC_MODL --ADD
                ,0 GR_OFFC_ID 
                 ,0 GR_BRNC_ID
        FROM    (
                    SELECT  MAX(T1.BASE_YW) BASE_YW
                            ,T1.BRNC_ID
                            ,T1.OFFC_ID
                            ,T1.MKT_MODL_ID
                            ,T1.BASC_MODL
                            ,T1.BI_CHNL_TP_02
                            ,T1.BI_CHNL_TP_03
                           
                            ,MAX(T1.BRNC_ID_NM) BRNC_ID_NM
                            ,MAX(T1.OFFC_ID_NM) OFFC_ID_NM
                            ,MAX(T1.MKT_MODL_ID) MKT_MODL_DI_NM
                            ,MAX(T1.BASC_MODL) BASC_MODL_NM
                            ,MAX(T1.BI_CHNL_TP_02_NM) BI_CHNL_TP_02_NM
                            ,MAX(T1.BI_CHNL_TP_03_NM) BI_CHNL_TP_03_NM
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 1 THEN SHOP_ID END) YW_01_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 2 THEN SHOP_ID END) YW_02_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 3 THEN SHOP_ID END) YW_03_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 4 THEN SHOP_ID END) YW_04_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 5 THEN SHOP_ID END) YW_05_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 6 THEN SHOP_ID END) YW_06_SHOP_CNT
                    FROM    T_MART T1
                    WHERE   NVL(T1.PSI_VAL,0) >= 1
                    GROUP BY T1.BRNC_ID
                            ,T1.OFFC_ID
                            ,T1.MKT_MODL_ID
                            ,T1.BASC_MODL
                            ,T1.BI_CHNL_TP_02
                            ,T1.BI_CHNL_TP_03
                ) T1
                ,T_SHOP_DIM T2
        WHERE   T1.BRNC_ID = T2.BRNC_ID
        AND     T1.OFFC_ID = T2.OFFC_ID
        AND     NVL(T1.BI_CHNL_TP_02,'-') = NVL(T2.BI_CHNL_TP_02,'-')
        AND     NVL(T1.BI_CHNL_TP_03,'-') = NVL(T2.BI_CHNL_TP_03,'-')
        UNION ALL
         
        SELECT  DISTINCT T1.BASE_YW
                ,T1.BRNC_ID
                ,'-' OFFC_ID
                ,'-' MKT_MODL_ID
                ,'-' BASC_MODL
                ,T1.BI_CHNL_TP_02
                ,T1.BI_CHNL_TP_03
                ,T1.BRNC_ID_NM
                ,T1.OFFC_ID_NM
                ,T1.MKT_MODL_DI_NM
                ,T1.BASC_MODL_NM
                ,T1.BI_CHNL_TP_02_NM
                ,T1.BI_CHNL_TP_03_NM
                ,SUM(T2.SHOP_CNT)OVER(PARTITION BY T1.BASE_YW,T1.BRNC_ID,T1.BI_CHNL_TP_02,T1.BI_CHNL_TP_03)SHOP_CNT
                ,T1.YW_01_SHOP_CNT
                ,T1.YW_02_SHOP_CNT
                ,T1.YW_03_SHOP_CNT
                ,T1.YW_04_SHOP_CNT
                ,T1.YW_05_SHOP_CNT
                ,T1.YW_06_SHOP_CNT
               
                ,0 GR_BI_CHNL_TP_02
                ,0 GR_BI_CHNL_TP_03
                ,1 GR_MKT_MODL_ID --ADD
                ,1 GR_BASC_MODL --ADD
                ,1 GR_OFFC_ID 
                 ,0 GR_BRNC_ID
        FROM    (
                    SELECT  MAX(T1.BASE_YW) BASE_YW
                            ,T1.BRNC_ID
                           -- ,T1.OFFC_ID
                            --,T1.MKT_MODL_ID
                            --,T1.BASC_MODL
                            ,T1.BI_CHNL_TP_02
                            ,T1.BI_CHNL_TP_03
                           
                            ,MAX(T1.BRNC_ID_NM) BRNC_ID_NM
                            ,'TTL' OFFC_ID_NM
                            ,'TTL' MKT_MODL_DI_NM --ADD
                            ,'TTL' BASC_MODL_NM   --ADD
                            ,MAX(T1.BI_CHNL_TP_02_NM) BI_CHNL_TP_02_NM
                            ,MAX(T1.BI_CHNL_TP_03_NM) BI_CHNL_TP_03_NM
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 1 THEN SHOP_ID END) YW_01_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 2 THEN SHOP_ID END) YW_02_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 3 THEN SHOP_ID END) YW_03_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 4 THEN SHOP_ID END) YW_04_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 5 THEN SHOP_ID END) YW_05_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 6 THEN SHOP_ID END) YW_06_SHOP_CNT
                    FROM    T_MART T1
                    WHERE   NVL(T1.PSI_VAL,0) >= 1
                    GROUP BY T1.BRNC_ID
                            --,T1.OFFC_ID
                            --,T1.MKT_MODL_ID
                            --,T1.BASC_MODL
                            ,T1.BI_CHNL_TP_02
                            ,T1.BI_CHNL_TP_03
                ) T1
                ,T_SHOP_DIM T2
        WHERE   T1.BRNC_ID = T2.BRNC_ID
       -- AND     T1.OFFC_ID = T2.OFFC_ID
        AND     NVL(T1.BI_CHNL_TP_02,'-') = NVL(T2.BI_CHNL_TP_02,'-')
        AND     NVL(T1.BI_CHNL_TP_03,'-') = NVL(T2.BI_CHNL_TP_03,'-')

 
UNION ALL
……
有些统计报表的sql编写过于复杂,常常是如上的形式,多个union到一起,且不同字段组合在一起分组计算,工作中遇到上面这样的类似sql,由11个上面的select语句块 union到一起,统计出2000条数据要2分钟。这样的语句不在少数而且有时会手工修改满足更改的报表需求,为提高sql运行和维护sql效率,必然需要优化。
对于这类union很多的分组计算的sql常常想到用报表分析函数合并,这样类似cube的报表函数要比union all的效率高,io少,因此首要优化的想法就是用更高效的报表分析函数合并这些union语句。但看过具体实际的例子会发现很多select都带有自己的查询条件,上面这段sql每个select还和另一个查询集合关联,且每次连接的条件都不一样。这样就要找到一种通用的方式才能合并这样的sql
首先在分析sql的时候发现,sql中的select中都有distinct这样的关键字,经与开发人员分析后改distinct的存在主要是为了分析函数求出的商店总数,而对于这个商店总数在 T_SHOP_DIM中是可以计算的,于是首先在T_SHOP_DIM计算商店总数
 SELECT         SUM(T1.SHOP_CNT) SHOP_CNT
                  FROM T_SHOP_DIM T1
                  GROUP BY (T1.BRNC_ID,T1.BI_CHNL_TP_02,T1.BI_CHNL_TP_03)
计算后在与T1表关联,于是首先去掉distinct的排中方法。
继续观察分析sql,T_SHOP_DIM的计算也是根据不同情况分组计算的,这个情况和T1集合中的分组情况是一致的,而关联条件也可以想办法根据不同的分组情况动态的设置成相应值,比如OFFC_ID在本次分组中未加入group by list中,这时就可以设置该值为’-’ ,而T1集合中的OFFC_ID也可以设置成’-’,这样在对应到本次分组连接时两个字段就能连接了。连接的形式固定了,就可以采用分组分析函数合并union all了,于是最终优化sql是
SELECT  MAX(T1.BASE_YW) BASE_YW
                            ,T1.BRNC_ID
                            ,(CASE WHEN GROUPING(T1.OFFC_ID)=1 THEN '-' ELSE T1.OFFC_ID END) OFFC_ID--,'-' OFFC_ID-- ,T1.OFFC_ID
                            ,(CASE WHEN GROUPING(T1.MKT_MODL_ID)=1 THEN '-' ELSE T1.MKT_MODL_ID END) MKT_MODL_ID--'-' MKT_MODL_ID --,T1.MKT_MODL_ID
                            ,(CASE WHEN GROUPING(T1.BASC_MODL)=1 THEN '-' ELSE T1.BASC_MODL END) BASC_MODL--'-' BASC_MODL --,T1.BASC_MODL
                            ,T1.BI_CHNL_TP_02
                            ,T1.BI_CHNL_TP_03
                           
                            ,MAX(T1.BRNC_ID_NM) BRNC_ID_NM
                            ,(CASE WHEN GROUPING(T1.OFFC_ID)=1 THEN 'TTL' ELSE MAX(T1.OFFC_ID_NM) END) OFFC_ID_NM--'TTL' OFFC_ID_NM
                            ,(CASE WHEN GROUPING(T1.MKT_MODL_ID)=1 THEN 'TTL' ELSE MAX(T1.MKT_MODL_ID) END) MKT_MODL_DI_NM--'TTL' MKT_MODL_DI_NM --ADD
                            ,(CASE WHEN GROUPING(T1.BASC_MODL)=1 THEN 'TTL' ELSE MAX(T1.BASC_MODL) END) BASC_MODL_NM--'TTL' BASC_MODL_NM   --ADD
                            ,MAX(T1.BI_CHNL_TP_02_NM) BI_CHNL_TP_02_NM
                            ,MAX(T1.BI_CHNL_TP_03_NM) BI_CHNL_TP_03_NM
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 1 THEN SHOP_ID END) YW_01_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 2 THEN SHOP_ID END) YW_02_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 3 THEN SHOP_ID END) YW_03_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 4 THEN SHOP_ID END) YW_04_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 5 THEN SHOP_ID END) YW_05_SHOP_CNT
                            ,COUNT(DISTINCT CASE WHEN T1.YW_RNK = 6 THEN SHOP_ID END) YW_06_SHOP_CNT
                            ,GROUPING_ID(T1.BRNC_ID) C1
                            ,CASE WHEN MAX(T1.OFFC_ID) IS NULL THEN GROUPING_ID(T1.BRNC_ID) END C2
                            ,GROUPING_ID(T1.BRNC_ID,T1.BI_CHNL_TP_02) C3
                            ,GROUPING_ID(T1.BRNC_ID,T1.OFFC_ID,T1.BI_CHNL_TP_02,T1.BI_CHNL_TP_03) C4

                            ,GROUPING(T1.BI_CHNL_TP_02) GR_BI_CHNL_TP_02
                            ,GROUPING(T1.BI_CHNL_TP_03) GR_BI_CHNL_TP_03
                            ,GROUPING(T1.MKT_MODL_ID) GR_MKT_MODL_ID --ADD
                            ,GROUPING(T1.BASC_MODL) GR_BASC_MODL --ADD
                            ,GROUPING(T1.OFFC_ID) GR_OFFC_ID 
                             ,GROUPING(T1.BRNC_ID) GR_BRNC_ID
                    FROM    T_MART T1
                    WHERE   NVL(T1.PSI_VAL,0) >= 1
                    GROUP BY GROUPING SETS( (T1.BRNC_ID,T1.BI_CHNL_TP_02,T1.BI_CHNL_TP_03)
                                          ,(T1.BRNC_ID,T1.OFFC_ID,T1.MKT_MODL_ID,T1.BASC_MODL,T1.BI_CHNL_TP_02,T1.BI_CHNL_TP_03)
                                         )

                ) T1
                ,(SELECT (CASE WHEN GROUPING(T1.BRNC_ID) = 1 THEN '-' ELSE T1.BRNC_ID END) BRNC_ID
                        ,(CASE WHEN GROUPING(T1.OFFC_ID) = 1 THEN '-' ELSE T1.OFFC_ID END) OFFC_ID
                        ,(CASE WHEN GROUPING(BI_CHNL_TP_02) = 1 THEN '-' ELSE T1.BI_CHNL_TP_02 END) BI_CHNL_TP_02
                        ,(CASE WHEN GROUPING(BI_CHNL_TP_03) = 1 THEN '-' ELSE T1.BI_CHNL_TP_03 END) BI_CHNL_TP_03
                        ,SUM(T1.SHOP_CNT) SHOP_CNT
                  FROM T_SHOP_DIM T1
                  GROUP BY GROUPING SETS( (T1.BRNC_ID,T1.BI_CHNL_TP_02,T1.BI_CHNL_TP_03)
                                        ,(T1.BRNC_ID,T1.OFFC_ID,T1.BI_CHNL_TP_02,T1.BI_CHNL_TP_03)
                                        )
                 ) T2
        WHERE   T1.BRNC_ID = T2.BRNC_ID
        AND     T1.OFFC_ID = T2.OFFC_ID
        AND     NVL(T1.BI_CHNL_TP_02,'-') = NVL(T2.BI_CHNL_TP_02,'-')
        AND     NVL(T1.BI_CHNL_TP_03,'-') = NVL(T2.BI_CHNL_TP_03,'-')

这样根据不同的统计情况,还可以在group by grouping set中添加其他统计情况,这样核心的sql合并后再统计的效率是47s,因此采用合适的分组分析函数对sql的效率和维护都是非常有必要的。

时间: 2024-08-15 05:35:36

执行长达2分多钟的大型sql优化的相关文章

分多钟擦额外看今天听明白

问题描述 分多钟擦额外看今天听明白 一个全局变量list来接受数据. button click的时候new一个新线程获取数据并调用hander处理数据. club.jd.com/CommunityGroupDetail/10491173_1.html club.jd.com/CommunityGroupDetail/10491144_1.html club.jd.com/CommunityGroupDetail/10490969_1.html club.jd.com/CommunityGroup

减少HTTP请求之将图片转成二进制并生成Base64编码,可以在网页中通过url查看图片(大型网站优化技术)

原文:减少HTTP请求之将图片转成二进制并生成Base64编码,可以在网页中通过url查看图片(大型网站优化技术) 在网站开发过程中,对于页面的加载效率一般都想尽办法求快.那么,怎么让才能更快呢?减少页面请求 是一个优化页面加载速度很好的方法.上一篇博文我们讲解了 "利用将小图标合成一张背景图来减少HTTP请求",那么,这一篇博文将讲解  " 将图片转成二进制并生成Base64编码,可以在网页中通过url查看图片". 一.为何选择将图片转成二进制并生成Base64编

大型网站优化策略

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 本人做站3年,没有什么技巧,做就可以了.直接进入主体 大型网站优化策略 NO.1 关键词分析 一.选择关键词的基本原则: 调查用户的搜索习惯 关键词不能过于宽泛 关键词不能过于"冷" 关键词要与页面内容保持高度的相关性 案例分析,有情趣的可以进去看看 网址大全 (www.ok100.net.cn) 关键词:网址大全,网址,

李京林:大型网站优化必修课-快速分析竞争对手

大型网站优化,是很多seoer喜欢的工作,作为媒体型的大型网站企业,往往有专职的美工程序,专职的编辑团队,经过seoer合理的seo建议,往往仅仅通过站内优化就能实现很好的效果. 而经历了目前互联网的高速发展,目前在互联网上,可以说已经没有蓝海型的领域了,每个领域,都可以说是一大俩小的竞争模型支撑着(一个很强的大站,两个小一点的弱一点的网站紧跟期后,每个领域都这样,不信你查查看^_^),所以说任何领域,你都是有竞争对手的.对应到seo优化上,竞争对手的分析,就显得尤为重要. 那么如何快速的分析竞

大众点评vs丁丁网大型网站优化对比

中介交易 SEO诊断 淘宝客 云主机 技术大厅 先通过爱站看一表面的数据, 三月平均:365 流量预估:IP≈ 1,908,000 PV≈ 12,821,760 dianping 三月平均:1,456 流量预估:IP≈ 486,000 PV≈ 2,123,820 ddmap 域名年龄 5年11个月2天(创建于2005年6月22日) dianping 域名年龄 5年6个月17天(创建于2005年11月8日) ddmap Pr值全部为7 百度 谷歌 雅虎 搜搜 收录数量 11600000 -5150

■■■■ 100分求VB.net访问sql server2000数据库的封装类及其用法 ■■■■

问题描述 请大家提供给我一个访问sqlserver2000数据库的访问类,包括连接数据库.操作数据库(datatable,dataset)等.注意:1.连接数据库的字符串(数据库名称.登录名称.登录密码等)是从config.xml中提取的.也就是这个字符串不是写死在类库中的.2.请尽量提供完整的类库3.请说明如何使用这个类库小弟初学VB.net,请大家帮助!谢谢!我的另外一个帖子,不过已经结贴了.http://topic.csdn.net/u/20071106/16/c10246de-4bfa-

200分!!!求SQL语句求高手

问题描述 declare@isEmptyint;set@isEmpty=0;Selecttop10*fromGy_StyleClassLangwith(nolock)where(casewhen@isEmpty=1then(titleisnotnullandtitle<>'')when@isEmpty=2then(titleisnullortitle='')else1=1end)我的意图如上,当参数值不同时列的条件也不同,希望大牛帮助一下,能不用ifelse尽量不要用 解决方案 解决方案二:这

生产环境大型sql语句调优实战第一篇(一)

在生产环境中有一条sql语句的性能极差,在早晨非高峰时段运行抽取数据,平均要花费40分钟,有时候竟然要跑10个多小时.sql语句比较长,需要点耐心往下看.我对表的数据量都做了简单的说明. 首先拿到sql语句,一看到关联的表有一长串,而且都是很大的表.如果性能很差,可能和走全表扫描有关,还有可能和多表关联时,表的查取顺序也有一定的关系. SELECT   DISTINCT CA.L9_CONVERGENCE_CODE AS ATB2,                 CU.CUST_SUB_TYP

生产环境大型sql语句调优实战第一篇(二)

继续昨天的部分,上一篇的链接为: http://blog.itpub.net/23718752/viewspace-1217012/ 对这条大sql的性能瓶颈进行了分析.主要瓶颈在于一个很大的业务表,数据量在亿级.如果通过时间条件来过滤,会有5%以内的数据被过滤出来. 但是没有时间相关的索引字段,所以会走全表扫描,在目前的产品线中,这个大分区表的索引时严格控制的,所以最后经过测试和比对,还是考虑加并行来提高数据的查取速度. --查找性能瓶颈,根据反馈,查取的数据其实并不错,可能在几千条以内的样子