标量子查询改写优化

1.简单版:
  1. SELECT empno,
  2.        ename,
  3.        sal,
  4.        deptno,
  5.        (SELECT d.dname
  6.           FROM dept d
  7.          WHERE d.deptno = e.deptno)
  8.           AS dname
  9.   FROM emp e;
改写后:
  1. SELECT e.empno,
  2.        e.ename,
  3.        e.sal,
  4.        e.deptno,
  5.        D.DNAME AS dname
  6.   FROM emp e left join dept d on (d.deptno = e.deptno)

2.带聚合函数的标量子查询

  1. SELECT d.department_id,
  2.        d.department_name,
  3.        d.location_id,
  4.        NVL ( (SELECT SUM (e.salary)
  5.                 FROM hr.employees e
  6.                WHERE e.department_id = d.department_id),
  7.             0)
  8.           AS sum_sal
  9.   FROM hr.departments d;
改写后:
  1. SELECT d.department_id,
  2.        d.department_name,
  3.        d.location_id,
  4.        NVL (e.salary, 0) AS sum_sal
  5.   FROM hr.departments d
  6.        LEFT JOIN ( SELECT e.department_id, SUM (e.salary) salary
  7.                       FROM hr.employees e
  8.                   GROUP BY e.department_id) e
  9.           ON (e.department_id = d.department_id)

3.行转列优化标量子查询
  1. SELECT
  2. (SELECT ROUND(v,2) FROM F2 where F2.UMITM=F4101.IMITM AND m='1' and F2.UMUM=F4101.IMUOM1) AS M3,
  3. (SELECT ROUND(v,2) FROM F2 where F2.UMITM=F4101.IMITM AND m='2' and F2.UMUM=F4101.IMUOM1) AS KG,
  4. (SELECT ROUND(v,2) FROM F2 where F2.UMITM=F4101.IMITM AND m='3' and F2.UMUM=F4101.IMUOM1) AS KN,
  5. (SELECT ROUND(v,2) FROM F2 where F2.UMITM=F4101.IMITM AND m='4' and F2.UMUM=F4101.IMUOM1) AS MH,
  6. (SELECT ROUND(v,2) FROM F2 where F2.UMITM=F4101.IMITM AND m='5' and F2.UMUM=F4101.IMUOM1) AS ML,
  7. (SELECT ROUND(v,2) FROM F2 where F2.UMITM=F4101.IMITM AND m='6' and F2.UMUM=F4101.IMUOM1) AS MW,
  8. (SELECT MAX(BPUPRC)/10000 FROM F4106 WHERE TRIM(BPMCU) = 'ZX10' and BPCRCD='CNY' AND F4106.BPLITM = F4101.IMLITM) BPUPRC
  9.   FROM F4101, F4102
  10.  WHERE F4101.IMITM = F4102.IBITM
  11.        AND F4101.IMLITM = F4102.IBLITM
  12.        AND IBMCU <> 'ZX10'
  13.        AND IMDSC1 NOT LIKE '%CANCEL%'
  14.        AND ( IMSRP5 IN ('1', '6')
  15.             OR IMSRP3 IN ('37', '38')
  16.             OR IBLITM IN ('506000040') AND TRIM (IBMCU) = 'SF10')
改写后:
  1. WITH f0
  2.      AS (SELECT IMITM, IMUOM1, IMLITM
  3.            FROM F4101, F4102
  4.           WHERE F4101.IMITM = F4102.IBITM
  5.                 AND F4101.IMLITM = F4102.IBLITM
  6.                 AND IBMCU <> 'ZX10'
  7.                 AND IMDSC1 NOT LIKE '%CANCEL%'
  8.                 AND ( IMSRP5 IN ('1', '6')
  9.                      OR IMSRP3 IN ('37', '38')
  10.                      OR IBLITM IN ('506000040') AND TRIM (IBMCU) = 'SF10'))
  11. SELECT F2.M3 AS M3,
  12.        F2.KG AS KG,
  13.        F2.KN AS KN,
  14.        F2.MH AS MH,
  15.        F2.ML AS ML,
  16.        F2.MW AS MW,
  17.        F4106.BPUPRC AS BPUPRC
  18.   FROM f0
  19.        LEFT JOIN ( SELECT UMITM,
  20.                            UMUM,
  21.                            MAX (CASE WHEN m = '1' THEN ROUND (v, 2) END) AS M3,
  22.                            MAX (CASE WHEN m = '2' THEN ROUND (v, 2) END) AS KG,
  23.                            MAX (CASE WHEN m = '3' THEN ROUND (v, 2) END) AS KN,
  24.                            MAX (CASE WHEN m = '4' THEN ROUND (v, 2) END) AS MH,
  25.                            MAX (CASE WHEN m = '5' THEN ROUND (v, 2) END) AS ML,
  26.                            MAX (CASE WHEN m = '6' THEN ROUND (v, 2) END) AS MW
  27.                       FROM F2
  28.                   GROUP BY UMITM, UMUM) F2
  29.           ON (F2.UMITM = f0.IMITM AND F2.UMUM = f0.IMUOM1)
  30.        LEFT JOIN ( SELECT BPLITM, MAX (BPUPRC) / 10000 BPUPRC
  31.                       FROM F4106
  32.                      WHERE TRIM (BPMCU) = 'ZX10' AND BPCRCD = 'CNY'
  33.                   GROUP BY BPLITM) F4106
  34.           ON (F4106.BPLITM = f0.IMLITM)

4.不等连接的标量子查询改写(一)
  1. SELECT a.licenceid,
  2.        a.data_source,
  3.        a.street,
  4.        (SELECT MIN (contdate)
  5.           FROM ct
  6.          WHERE ct.licenceid = a.licenceid
  7.                AND ct.data_source = a.data_source
  8.                AND TRUNC (contdate) >= a.opensaledate)
  9.           AS mincontdate,
  10.        (SELECT MIN (buydate)
  11.           FROM ct
  12.          WHERE ct.licenceid = a.licenceid
  13.                AND ct.data_source = a.data_source
  14.                AND TRUNC (buydate) >= a.opensaledate)
  15.           AS minbuydate
  16.   FROM a
改写后:
  1. with ct2 as
  2. (
  3.     select rowid as rid,
  4. min(case when TRUNC (contdate) >= a.opensaledate then contdate end),
  5. min(case when TRUNC (buydate) >= a.opensaledate then buydate end)
  6. from ct , a
  7. where ct.licenceid = a.licenceid
  8. AND ct.data_source = a.data_source
  9. group by rowid
  10. )
  11. SELECT a.licenceid,
  12.        a.data_source,
  13.        a.street,
  14.        ct2.mincontdate AS mincontdate,
  15.        ct2.minbuydate AS minbuydate
  16.   FROM a left join ct2 on (ct2.rid = a.rowid)

5.不等连接的标量子查询改写(二)
  1. SELECT s.stkcode,
  2.        t.mktcode,
  3.        t.stype,
  4.        t.sname,
  5.        (SELECT SUM (c.hs1)
  6.           FROM c
  7.          WHERE c.stkcode = s.stkcode
  8.                AND c.mktcode = t.mktcode
  9.                AND c.calcdate BETWEEN TO_CHAR (
  10.                                          TO_DATE (s.tdate, 'yyyymmdd') - 365,
  11.                                          'yyyymmdd')
  12.                                   AND s.tdate)
  13.           AS f1,
  14.        (SELECT DECODE (COUNT (c.calcdate),
  15.                        0, NULL,
  16.                        SUM (c.hs1) / COUNT (c.calcdate))
  17.           FROM c
  18.          WHERE c.stkcode = s.stkcode
  19.                AND c.mktcode = t.mktcode
  20.                AND c.calcdate BETWEEN TO_CHAR (
  21.                                          TO_DATE (s.tdate, 'yyyymmdd') - 365,
  22.                                          'yyyymmdd')
  23.                                   AND s.tdate)
  24.           AS f2,
  25.        s.tdate
  26.   FROM s, t
  27.  WHERE s.stkcode = t.scode
  28.        AND t.status = 1
  29.        AND t.stype = 2
  30.        AND s.tdate >= TO_NUMBER (TO_CHAR (SYSDATE - 3, 'yyyymmdd'));
改写后:
(1).
  1. with t0 as
  2. (select rownum as sn, s.*,t.*
  3.     FROM s, t
  4.  WHERE s.stkcode = t.scode
  5.        AND t.status = 1
  6.        AND t.stype = 2
  7.        AND s.tdate >= TO_NUMBER (TO_CHAR (SYSDATE - 3, 'yyyymmdd'))
  8. )
  9. SELECT t.stkcode,
  10.        t.mktcode,
  11.        t.stype,
  12.        t.sname,
  13.        ha.f1 AS f1,
  14.        ha.f2 AS f2,
  15.        t.tdate
  16.   FROM t0 t left join ( SELECT t0.sn,
  17.          SUM (c.hs1) f1,
  18.          DECODE (COUNT (c.calcdate), 0, NULL, SUM (c.hs1) / COUNT (c.calcdate))
  19.             f2
  20.     FROM c, t0
  21.    WHERE c.stkcode = t0.stkcode
  22.          AND c.mktcode = t0.mktcode
  23.          AND c.calcdate BETWEEN TO_CHAR (TO_DATE (t0.tdate, 'yyyymmdd') - 365,
  24.                                          'yyyymmdd')
  25.                             AND t0.tdate
  26. GROUP BY t0.sn) ha on (ha.sn = t0.sn)
(2).
  1. WITH t0
  2.      AS (SELECT ROWNUM AS sn, s.*, t.*
  3.            FROM s, t
  4.           WHERE s.stkcode = t.scode
  5.                 AND t.status = 1
  6.                 AND t.stype = 2
  7.                 AND s.tdate >= TO_NUMBER (TO_CHAR (SYSDATE - 3, 'yyyymmdd')))
  8.   SELECT s.stkcode,
  9.          t.mktcode,
  10.          t.stype,
  11.          t.sname,
  12.          SUM (c.hs1) AS f1,
  13.          DECODE (COUNT (c.calcdate), 0, NULL, SUM (c.hs1) / COUNT (c.calcdate))
  14.             AS f2,
  15.          s.tdate
  16.     FROM t0 t LEFT JOIN c ON (c.stkcode = t.stkcode AND c.mktcode = t.mktcode)
  17.    WHERE c.calcdate BETWEEN TO_CHAR (TO_DATE (s.tdate, 'yyyymmdd') - 365,
  18.                                      'yyyymmdd')
  19.                         AND s.tdate
  20. GROUP BY t.sn,
  21.          t.stkcode,
  22.          t.mktcode,
  23.          t.stype,
  24.          t.sname,
  25.          s.tdate

6. 标量子查询DISTINCT
  1. SELECT *
  2.   FROM (SELECT *
  3.           FROM t1
  4.          WHERE col4_1 = '00') a
  5.        LEFT JOIN
  6.        (SELECT col3_1,
  7.                col3_2 col1,
  8.                col2,
  9.                (SELECT DISTINCT col2_1
  10.                   FROM t2
  11.                  WHERE col2_2 = a.col2
  12.                        AND col2_3 <= TO_DATE ( ('2012-09-30'), 'yyyy-mm-dd')
  13.                        AND col2_4 > TO_DATE ('2012-09-30', 'yyyy-mm-dd'))
  14.                   col3
  15.           FROM t3 a
  16.          WHERE col2_3 <= TO_DATE ('2012-09-30', 'yyyy-mm-dd')
  17.                AND col2_4 > TO_DATE ('2012-09-30', 'yyyy-mm-dd')) b
  18.           ON (a.col4 = b.col3_1)
改写后:
  1. SELECT *
  2.   FROM (SELECT *
  3.           FROM t1
  4.          WHERE col4_1 = '00') a
  5.        LEFT JOIN
  6.        (SELECT col3_1,
  7.                col3_2 col1,
  8.                col2,
  9.                col3.col2_1 col3
  10.           FROM t3 a
  11.                LEFT JOIN
  12.                ( SELECT col2_1, col2_2
  13.                     FROM t2
  14.                    WHERE col2_3 <=
  15.                                 TO_DATE ( ('2012-09-30'),
  16.                                          'yyyy-mm-dd')
  17.                          AND col2_4 >
  18.                                 TO_DATE ('2012-09-30', 'yyyy-mm-dd')
  19.                 GROUP BY col2_1, col2_2) col3
  20.                   ON (col3.col2_2 = a.col2)
  21.          WHERE col2_3 <= TO_DATE ('2012-09-30', 'yyyy-mm-dd')
  22.                AND col2_4 > TO_DATE ('2012-09-30', 'yyyy-mm-dd')) b
  23.           ON (a.col4 = b.col3_1)


7.分析函数优化标量子查询(一)

当标量子查询中的表与主查询中的表一样,也就是有自关联的时候,常常可以改用分析函数直接取值。


未完。。。








来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/15412087/viewspace-2148428/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/15412087/viewspace-2148428/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值