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

简介: 在工作中,有些报表的展示较复杂,且需要统计的内容不断变化,开发的sql越来越长,运行越来越慢,这时优化必不可免,先来看下如下冗长的执行了2分多钟的sql,看看从中是否能找出些规律 SELECT  T1.
在工作中,有些报表的展示较复杂,且需要统计的内容不断变化,开发的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的效率和维护都是非常有必要的。

目录
相关文章
|
8月前
|
SQL 存储 监控
SQL日志优化策略:提升数据库日志记录效率
通过以上方法结合起来运行调整方案, 可以显著地提升SQL环境下面向各种搜索引擎服务平台所需要满足标准条件下之数据库登记作业流程综合表现; 同时还能确保系统稳健运行并满越用户体验预期目标.
410 6
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(07) 她气鼓鼓递来一条SQL | 怎么看执行计划、SQL怎么优化?
在日常研发工作当中,系统性能优化,从大的方面来看主要涉及基础平台优化、业务系统性能优化、数据库优化。面对数据库优化,除了DBA在集群性能、服务器调优需要投入精力,我们研发需要负责业务SQL执行优化。当业务数据量达到一定规模后,SQL执行效率可能就会出现瓶颈,影响系统业务响应。掌握如何判断SQL执行慢、以及如何分析SQL执行计划、优化SQL的技能,在工作中解决SQL性能问题显得非常关键。
|
SQL 存储 自然语言处理
SQL的解析和优化的原理:一条sql 执行过程是什么?
SQL的解析和优化的原理:一条sql 执行过程是什么?
SQL的解析和优化的原理:一条sql 执行过程是什么?
|
SQL 关系型数据库 MySQL
如何优化SQL查询以提高数据库性能?
这篇文章以生动的比喻介绍了优化SQL查询的重要性及方法。它首先将未优化的SQL查询比作在自助餐厅贪多嚼不烂的行为,强调了只获取必要数据的必要性。接着,文章详细讲解了四种优化策略:**精简选择**(避免使用`SELECT *`)、**专业筛选**(利用`WHERE`缩小范围)、**高效联接**(索引和限制数据量)以及**使用索引**(加速搜索)。此外,还探讨了如何避免N+1查询问题、使用分页限制结果、理解执行计划以及定期维护数据库健康。通过这些技巧,可以显著提升数据库性能,让查询更高效流畅。
|
SQL 关系型数据库 MySQL
基于SQL Server / MySQL进行百万条数据过滤优化方案
对百万级别数据进行高效过滤查询,需要综合使用索引、查询优化、表分区、统计信息和视图等技术手段。通过合理的数据库设计和查询优化,可以显著提升查询性能,确保系统的高效稳定运行。
849 9
|
SQL Oracle 关系型数据库
如何在 Oracle 中配置和使用 SQL Profiles 来优化查询性能?
在 Oracle 数据库中,SQL Profiles 是优化查询性能的工具,通过提供额外统计信息帮助生成更有效的执行计划。配置和使用步骤包括:1. 启用自动 SQL 调优;2. 手动创建 SQL Profile,涉及收集、执行调优任务、查看报告及应用建议;3. 验证效果;4. 使用 `DBA_SQL_PROFILES` 视图管理 Profile。
|
SQL 缓存 监控
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
本文详细解析了数据库、缓存、异步处理和Web性能优化四大策略,系统性能优化必知必备,大厂面试高频。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
|
SQL Oracle 数据库
使用访问指导(SQL Access Advisor)优化数据库业务负载
本文介绍了Oracle的SQL访问指导(SQL Access Advisor)的应用场景及其使用方法。访问指导通过分析给定的工作负载,提供索引、物化视图和分区等方面的优化建议,帮助DBA提升数据库性能。具体步骤包括创建访问指导任务、创建工作负载、连接工作负载至访问指导、设置任务参数、运行访问指导、查看和应用优化建议。访问指导不仅针对单条SQL语句,还能综合考虑多条SQL语句的优化效果,为DBA提供全面的决策支持。
421 11
|
SQL 缓存 数据库
SQL慢查询优化策略
在数据库管理和应用开发中,SQL查询的性能优化至关重要。慢查询优化不仅可以提高应用的响应速度,还能降低服务器负载,提升用户体验。本文将详细介绍针对SQL慢查询的优化策略。
|
SQL 存储 缓存
如何优化SQL查询性能?
【10月更文挑战第28天】如何优化SQL查询性能?
1031 10