优化有标量子查询的SQL

数据库环境:SQL SERVER 2008R2

今天在数据库中抓出一条比较耗费资源的SQL,只返回904条数据,居然跑了40多分钟。SQL及对应的数据量如下图:

SELECT  saft04.cur_year ,
        LEFT(saft04.dept_id, 4) sdept_id ,
        saft04.vdept_id ,
        saft04.dept_id ,
        saft04.fee_id ,
        saft04.vitem_id ,
        ISNULL(saft04.fee_amt, 0) AS saft04_fee_amt ,
        ISNULL(saft04.fee_qty, 0) AS saft04_fee_qty ,
        ISNULL(saft04.fee_amt_flex, 0) AS saft04_fee_amt_flex ,
        ISNULL(saft04.adj_amt, 0) AS saft04_adj_amt ,
        ISNULL(saft04.init_amt, 0) AS saft04_init_amt ,
        ISNULL(saft04.flex_amt, 0) AS saft04_flex_amt ,
        ISNULL(saft04.conf_fee_amt, 0) AS saft04_conf_fee_amt ,
        saft04.fc_app_no ,
        saft04.zone_id ,
        saft04.corr_id ,
        CASE WHEN saft04.fc_app_no < '2010'
             THEN ( CASE WHEN saft04.flexfapp_flag = 'Y'
                         THEN ISNULL(fee_amt, 0) + ISNULL(adj_amt, 0)
                              - ISNULL(conf_fee_amt, 0)
                         ELSE ISNULL(init_amt, 0) + ISNULL(flex_amt, 0)
                              + ISNULL(adj_amt, 0) - ISNULL(conf_fee_amt, 0)
                    END )
             ELSE CASE WHEN b.fee_type2 = '01'
                            OR b.fee_type2 = '02'
                       THEN ISNULL(fee_amt, 0) + ISNULL(adj_amt, 0)
                            - ISNULL(conf_fee_amt, 0)
                       WHEN b.fee_type2 = '03'
                       THEN ISNULL(init_amt, 0) + ISNULL(flex_amt, 0)
                            + ISNULL(adj_amt, 0) - ISNULL(conf_fee_amt, 0)
                  END
        END bal_amt ,
        ISNULL(( SELECT SUM(b.opr_amt)
                 FROM   v_saft04_fexp b
                 WHERE  b.fcapp_id = saft04.fc_app_no
               ), 0) AS qty1 ,
        CASE WHEN b.fee_type2 = '01'
                  OR b.fee_type2 = '03'
             THEN ISNULL(saft04.conf_fee_amt, 0)
                  - ( ISNULL(( SELECT   SUM(b.opr_amt)
                               FROM     v_saft04_fexp b
                               WHERE    b.fcapp_id = saft04.fc_app_no
                             ), 0) )
             WHEN b.fee_type2 = '02'
             THEN ISNULL(saft04.init_amt, 0) + ISNULL(saft04.flex_amt, 0)
                  - ISNULL(( SELECT SUM(b.opr_amt)
                             FROM   v_saft04_fexp b
                             WHERE  b.fcapp_id = saft04.fc_app_no
                           ), 0)
                  + ISNULL(( SELECT SUM(d.opr_amt)
                             FROM   v_fadj_rd d
                             WHERE  d.fcapp_id = saft04.fc_app_no
                           ), 0)
        END qty2 ,
        c.base_data2
FROM    saft04
        LEFT JOIN v_ctlm60 b ON b.fee_id = saft04.fee_id
        LEFT JOIN ctlm1000 c ON c.d_type = 'fee_type2'
                                AND b.fee_type2 = c.base_data1
WHERE   1 = 1
        AND saft04.com_id = 'LQPJ'
        AND saft04.cur_year = 2015
        AND saft04.dept_id LIKE '2001%'
        AND ( saft04.dept_id IN ( SELECT    dept_id
                                  FROM      ctlm2000
                                  WHERE     user_id1 = '0100030' )
              OR '0100030' = 'MANAGER'
            )
ORDER BY saft04.cur_year ,
        saft04.vdept_id ,
        saft04.dept_id ,
        saft04.fee_id ,
        saft04.vitem_id ,
        saft04.zone_id ,
        saft04.corr_id ,
        saft04.fc_app_no
-------------------------数据量统计----------------------------------
SELECT  COUNT(*)
FROM    saft04
WHERE   1 = 1
        AND saft04.com_id = 'LQPJ'
        AND saft04.cur_year = 2015
        AND saft04.dept_id LIKE '%2001%'
        AND ( saft04.dept_id IN ( SELECT    dept_id
                                  FROM      ctlm2000
                                  WHERE     user_id1 = '0100030' )
              OR '0100030' = 'MANAGER'
            )--904
SELECT COUNT(*) FROM  v_saft04_fexp  --1262584
SELECT COUNT(*) FROM  v_fadj_rd d --37077
SELECT COUNT(*) FROM  v_ctlm60 --431
SELECT COUNT(*) FROM  ctlm1000 --377

看了一下SQL,有可能出现问题的地方有2个地方,第一个是saft04 表的过滤条件“saft04.dept_id LIKE '%2001%'”使用了模糊查询,导致

走不了既定的索引。经和业务员确定,最开始只是想查询以“2001”开头的单位,因此,这个条件改成“saft04.dept_id LIKE '2001%'”即可。

第二个问题,是最要命的,标量部分“SELECT SUM(b.opr_amt) FROM v_saft04_fexp b WHERE b.fcapp_id = saft04.fc_app_no”走

的执行计划是嵌套循环,因而要改成左联接。

改写后的SQL如下,只执行了23S就全部出结果了。

 

WITH    x0
          AS ( SELECT   b.fcapp_id ,
                        SUM(b.opr_amt) opr_amt
               FROM     v_saft04_fexp b
               GROUP BY b.fcapp_id
             )
    SELECT  saft04.cur_year ,
            LEFT(saft04.dept_id, 4) sdept_id ,
            saft04.vdept_id ,
            saft04.dept_id ,
            saft04.fee_id ,
            saft04.vitem_id ,
            ISNULL(saft04.fee_amt, 0) AS saft04_fee_amt ,
            ISNULL(saft04.fee_qty, 0) AS saft04_fee_qty ,
            ISNULL(saft04.fee_amt_flex, 0) AS saft04_fee_amt_flex ,
            ISNULL(saft04.adj_amt, 0) AS saft04_adj_amt ,
            ISNULL(saft04.init_amt, 0) AS saft04_init_amt ,
            ISNULL(saft04.flex_amt, 0) AS saft04_flex_amt ,
            ISNULL(saft04.conf_fee_amt, 0) AS saft04_conf_fee_amt ,
            saft04.fc_app_no ,
            saft04.zone_id ,
            saft04.corr_id ,
            CASE WHEN saft04.fc_app_no < '2010'
                 THEN ( CASE WHEN saft04.flexfapp_flag = 'Y'
                             THEN ISNULL(fee_amt, 0) + ISNULL(adj_amt, 0)
                                  - ISNULL(conf_fee_amt, 0)
                             ELSE ISNULL(init_amt, 0) + ISNULL(flex_amt, 0)
                                  + ISNULL(adj_amt, 0) - ISNULL(conf_fee_amt,
                                                              0)
                        END )
                 ELSE CASE WHEN b.fee_type2 = '01'
                                OR b.fee_type2 = '02'
                           THEN ISNULL(fee_amt, 0) + ISNULL(adj_amt, 0)
                                - ISNULL(conf_fee_amt, 0)
                           WHEN b.fee_type2 = '03'
                           THEN ISNULL(init_amt, 0) + ISNULL(flex_amt, 0)
                                + ISNULL(adj_amt, 0) - ISNULL(conf_fee_amt, 0)
                      END
            END bal_amt ,
            ISNULL(( x0.opr_amt ), 0) AS qty1 ,
            CASE WHEN b.fee_type2 = '01'
                      OR b.fee_type2 = '03'
                 THEN ISNULL(saft04.conf_fee_amt, 0) - ( ISNULL(( x0.opr_amt ),
                                                              0) )
                 WHEN b.fee_type2 = '02'
                 THEN ISNULL(saft04.init_amt, 0) + ISNULL(saft04.flex_amt, 0)
                      - ISNULL(( x0.opr_amt ), 0)
                      + ISNULL(( SELECT SUM(d.opr_amt)
                                 FROM   v_fadj_rd d
                                 WHERE  d.fcapp_id = saft04.fc_app_no
                               ), 0)
            END qty2 ,
            c.base_data2
    FROM    saft04
            LEFT JOIN v_ctlm60 b ON b.fee_id = saft04.fee_id
            LEFT JOIN ctlm1000 c ON c.d_type = 'fee_type2'
                                    AND b.fee_type2 = c.base_data1
            LEFT JOIN x0 ON x0.fcapp_id = saft04.fc_app_no
    WHERE   1 = 1
            AND saft04.com_id = 'LQPJ'
            AND saft04.cur_year = 2015
            AND saft04.dept_id LIKE '2001%'
            AND saft04.dept_id IN ( SELECT  dept_id
                                    FROM    ctlm2000
                                    WHERE   user_id1 = '0100030' )
    ORDER BY saft04.cur_year ,
            saft04.vdept_id ,
            saft04.dept_id ,
            saft04.fee_id ,
            saft04.vitem_id ,
            saft04.zone_id ,
            saft04.corr_id ,
            saft04.fc_app_no

 

改写后的SQL还有一个标量子查询没处理,改写的思路和上面一样,因执行时间已经缩短到23S,就不改了。

 

转载于:https://www.cnblogs.com/boss-he/p/4611996.html

利用 TensorFlow 训练自己的目标识别器。本文内容来自于我的毕业设计,基于 TensorFlow 1.15.0,其他 TensorFlow 版本运行可能存在问题。.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
对于 Oracle 标量子查询中的 `LISTAGG` 函数,可以考虑以下几种优化方法: 1. 确保索引的使用:确保子查询中涉及的表上有适当的索引,以加快数据检索速度。如果子查询中使用了过滤条件,可以考虑在相关列上创建索引。 2. 限制结果集大小:如果子查询返回的结果集很大,可以考虑在子查询中添加适当的过滤条件,以限制结果集的大小。这可以减少 `LISTAGG` 函数处理的数据量,提高性能。 3. 使用内联视图:将子查询转换为内联视图(Inline View),可以避免多次执行子查询,从而提高性能。内联视图可以通过 WITH 子句或者嵌套查询的方式实现。 4. 考虑使用分析函数:如果子查询中需要对数据进行排序、分组或其他复杂的操作,可以考虑使用分析函数(Analytic Functions)来替代 `LISTAGG` 函数。分析函数通常比标量子查询更高效。 5. 优化查询计划:使用合适的查询提示(Query Hints)或者调整查询语句的结构,以促使 Oracle 生成更优化的查询计划。可以通过 EXPLAIN PLAN、SQL Trace 或者 SQL Monitoring 等工具来分析和优化查询计划。 6. 考虑使用其他技术:如果标量子查询的性能问题仍然存在,可以考虑使用其他技术来实现相同的功能,例如使用连接查询、临时表或者其他编程方式。 请注意,优化标量子查询涉及到具体的数据模型、查询语句和数据库配置等因素,因此需要根据具体情况进行分析和调整。建议在进行任何优化操作之前,先进行性能测试和评估,以确保优化策略的有效性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值