Oracle 使用 with as 優化重複查詢

我們有時寫的sql 會多次查詢和使用相同的結果集,而事實上每次查詢都會消耗資源和降低sql的整體查詢效率,特別是對大量數據表,耗時特別長。

使用with as 將想要查詢的數據集保存到一張虛表中,數據查詢均從這張虛擬表(視圖)中查詢獲得,減少對數據庫的直接訪問。

 1、該sql性能太低,其中有兩張表(數據量均比較大)數據拼接操作,沒有先過濾掉不需要的數據,全表掃描兩張大表然後拼接,然後過濾
SELECT A.CUST_ID,
               A.CUST_CODE,
               A.CUST_NAME,
               A.CREATED_DATE,
               A.CUST_TYPE,
               C.CERT_TYPE_NAME,
               B.CERT_NBR,
               D.STATE,
               D.STATE_DATE,
               E.MDN_STATE MSISDN_STATE
          FROM CUST A,
               CERT B,
               CERT_TYPE C,
               ECONET_CUST_STATE D,
               (SELECT G.CUST_ID, WM_CONCAT(G.MDN_STATE) MDN_STATE
                  FROM (SELECT *
                          FROM (SELECT F.CUST_ID,
                                       F.MDN_STATE,
                                       ROW_NUMBER() OVER(PARTITION BY F.CUST_ID ORDER BY F.MDN_STATE) TOP
                                  FROM (SELECT DISTINCT S.CUST_ID,
                                                        S.PREFIX || S.ACC_NBR || '|' ||
                                                        P.PROD_STATE MDN_STATE
                                          FROM SUBS S, PROD P
                                         WHERE S.SUBS_ID = P.PROD_ID) F)
                         WHERE TOP <= 5) G
                 WHERE G.CUST_ID IS NOT NULL
                 GROUP BY G.CUST_ID) E
         WHERE 1 = 1
           AND A.CUST_ID = D.CUST_ID
           AND A.CERT_ID = B.CERT_ID(+)
           AND B.CERT_TYPE_ID = C.CERT_TYPE_ID(+)
           AND A.CUST_ID = E.CUST_ID(+)
           AND D.STATE IN ('F', 'A', 'D')

2、第一次優化,先過濾掉數據然後拼接,然而部分數據由於拼接元素爲null,通過條件過濾的話會漏掉,因此要單獨查詢 然後union(性能有所提高)

SELECT G.CUST_ID,
            G.CUST_CODE,
            G.CUST_NAME,G.CREATED_DATE,G.CUST_TYPE,G.CERT_TYPE_NAME,
            G.CERT_NBR,G.STATE,G.STATE_DATE, WM_CONCAT(G.MDN_STATE) MDN_STATE
    FROM (SELECT *
            FROM (SELECT F.CUST_ID,
            F.CUST_CODE,
            F.CUST_NAME,F.CREATED_DATE,F.CUST_TYPE,F.CERT_TYPE_NAME,
            F.CERT_NBR,F.STATE,F.STATE_DATE,
                         F.MDN_STATE,
                         ROW_NUMBER() OVER(PARTITION BY F.CUST_ID ORDER BY F.MDN_STATE) TOP
                    FROM (  SELECT A.CUST_ID,
                                   A.CUST_CODE,
                                   A.CUST_NAME,
                                   A.CREATED_DATE,
                                   A.CUST_TYPE,
                                   C.CERT_TYPE_NAME,
                                   B.CERT_NBR,
                                   D.STATE,
                                   D.STATE_DATE,S.PREFIX || S.ACC_NBR || '|' ||P.PROD_STATE MDN_STATE
                            FROM SUBS S, PROD P, CUST A,CERT B,CERT_TYPE C, ECONET_CUST_STATE D
                            WHERE S.SUBS_ID = P.PROD_ID
                            AND B.CERT_TYPE_ID = C.CERT_TYPE_ID(+)
                            AND A.CERT_ID = B.CERT_ID(+)
                            AND A.CUST_ID  = S.CUST_ID(+)
                            AND A.CUST_ID = D.CUST_ID
                            AND D.STATE IN ('F', 'A', 'D')) F)
           WHERE TOP <= 5) G
   WHERE G.CUST_ID IS NOT NULL
   GROUP BY G.CUST_ID,
            G.CUST_CODE,
            G.CUST_NAME,G.CREATED_DATE,G.CUST_TYPE,G.CERT_TYPE_NAME,
            G.CERT_NBR,G.STATE,G.STATE_DATE
    UNION ALL
    SELECT A.CUST_ID,
                     A.CUST_CODE,
                     A.CUST_NAME,
                     A.CREATED_DATE,
                     A.CUST_TYPE,
                     C.CERT_TYPE_NAME,
                     B.CERT_NBR,
                     D.STATE,
                     D.STATE_DATE,WM_CONCAT(S.CUST_ID) MDN_STATE
                FROM CUST A,CERT B,CERT_TYPE C, ECONET_CUST_STATE D,SUBS S
                WHERE 1=1
                AND B.CERT_TYPE_ID = C.CERT_TYPE_ID(+)
                AND A.CERT_ID = B.CERT_ID(+)
                AND A.CUST_ID = D.CUST_ID
                AND D.CUST_ID  = S.CUST_ID(+)
                AND D.STATE IN ('F', 'A', 'D')
                AND S.CUST_ID IS NULL
GROUP BY A.CUST_ID,
                     A.CUST_CODE,
                     A.CUST_NAME,
                     A.CREATED_DATE,
                     A.CUST_TYPE,
                     C.CERT_TYPE_NAME,
                     B.CERT_NBR,
                     D.STATE,
                     D.STATE_DATE

3、第二次優化(第一次優化 使用了union all,其中SUBS S,CUST A,CERT B,CERT_TYPE C, ECONET_CUST_STATE D 這些個關聯查詢在union all 兩邊 都做了,如果只查詢一次的話,性能會更好點,因此抽出來,用with  as 先做一次查詢 保存SCCCE 這張虛表中  這樣只會對subs 這張數據量很大的表做一次全表掃描)

 WITH SCCCE AS (SELECT A.CUST_ID, 
                 S.SUBS_ID,                                          
                 A.CUST_CODE,
                 A.CUST_NAME,
                 A.CREATED_DATE,
                 A.CUST_TYPE,
                 C.CERT_TYPE_NAME,
                 B.CERT_NBR,
                 D.STATE,
                 D.STATE_DATE,
                 S.PREFIX || S.ACC_NBR MISDN            
          FROM SUBS S,CUST A,CERT B,CERT_TYPE C, ECONET_CUST_STATE D
          WHERE B.CERT_TYPE_ID = C.CERT_TYPE_ID(+)
          AND A.CERT_ID = B.CERT_ID(+)
          AND A.CUST_ID  = S.CUST_ID(+)
          AND A.CUST_ID = D.CUST_ID
          AND D.STATE IN ('F', 'A', 'D'))
          
   SELECT G.CUST_ID,
          G.CUST_CODE,
          G.CUST_NAME,G.CREATED_DATE,G.CUST_TYPE,G.CERT_TYPE_NAME,
          G.CERT_NBR,G.STATE,G.STATE_DATE, WM_CONCAT(G.MDN_STATE) MDN_STATE
      FROM (SELECT * 
            FROM (SELECT F.CUST_ID,
                          F.CUST_CODE,
                          F.CUST_NAME,F.CREATED_DATE,F.CUST_TYPE,F.CERT_TYPE_NAME,
                          F.CERT_NBR,F.STATE,F.STATE_DATE,
                          F.MDN_STATE,
                          ROW_NUMBER() OVER(PARTITION BY F.CUST_ID ORDER BY F.MDN_STATE) TOP
                  FROM (SELECT SC.CUST_ID,
                             SC.CUST_CODE,
                             SC.CUST_NAME,
                             SC.CREATED_DATE,
                             SC.CUST_TYPE,
                             SC.CERT_TYPE_NAME,
                             SC.CERT_NBR,
                             SC.STATE,
                             SC.STATE_DATE,
                             SC.MISDN|| '|' ||P.PROD_STATE MDN_STATE 
                       FROM PROD P,SCCCE SC
                       WHERE SC.SUBS_ID = P.PROD_ID)F)
           WHERE TOP <= 5) G
     WHERE G.CUST_ID IS NOT NULL
     GROUP BY G.CUST_ID,
              G.CUST_CODE,
              G.CUST_NAME,G.CREATED_DATE,G.CUST_TYPE,G.CERT_TYPE_NAME,
              G.CERT_NBR,G.STATE,G.STATE_DATE
     UNION ALL
     SELECT SC.CUST_ID,
          SC.CUST_CODE,
          SC.CUST_NAME,
          SC.CREATED_DATE,
          SC.CUST_TYPE,
          SC.CERT_TYPE_NAME,
          SC.CERT_NBR,
          SC.STATE,
          SC.STATE_DATE,WM_CONCAT( SC.MISDN) MDN_STATE
    FROM SCCCE SC
    WHERE 1=1           
    AND  SC.SUBS_ID IS NULL
    GROUP BY SC.CUST_ID,
           SC.CUST_CODE,
           SC.CUST_NAME,
           SC.CREATED_DATE,
           SC.CUST_TYPE,
           SC.CERT_TYPE_NAME,
           SC.CERT_NBR,
           SC.STATE,
           SC.STATE_DATE    


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章