2011-10-05 116 views
0

我想優化下面的查詢。我沒有關於優化技術的專業知識。 請建議我一些東西,可以幫我優化下面的查詢:Oracle查詢優化(帶連接和子查詢)

SELECT 
     ad.towncity, 
     ad.state, 

FROM promptdescription pd, 
     osquestion osq, 

WHERE acc.status = 1 
AND acc.customer_id = con.customer_id 
     ap.os_id 
AND NOT EXISTS (SELECT 1 
       FROM osquestion osq2, 
         orderedproduct op3 
       WHERE osq2.ext_quest_id = pd.id 
       AND osq2.question_id > osq.question_id 
+1

請參閱:http://stackoverflow.com/questions/761204/what-resources-exist-for-database-performance-tuning和http://stackoverflow.com/questions/3706750/sql-tuning-in-oracle –

+0

@yakub_moriss:也許一些不錯的縮進會吸引讀者。在目前的形式下,我不被它吸引。另外,我認爲導致這個查詢存在的人應該被槍殺。 – wildplasser

+0

@catcall:美麗!你甚至修復了醜陋的相關名稱。 – wildplasser

回答

0

首先,你的查詢等效於:

SELECT ACC.id 
    , OP.rootprODUCT_ID 
    , ACC.externALBILLID 
    , CON.firstnAME 
    , CON.lastnaME 
    , AD.line1 
    , NVL (AD.line2 , '') AS  LINE2 
    , AD.towncity 
    , AD.state 
    , AD.postalzipcode 
    , PROD.billingcode 
    , PD.name    as  Prompt_Name 
    , OSQ.current_value 
    FROM promptdescription    PD 
    JOIN osquestion     OSQ ON  OSQ.ext_quest_id =   PD.id 
    JOIN osquestiongroup   OSQGRP ON  OSQGRP.qg_id   =  OSQ.qg_id 
    JOIN osparamdatacapability OSPARAMCAP ON OSPARAMCAP.cap_id  =  OSQGRP.cap_id 
    JOIN orderedservice    OS ON   OS.id   = OSPARAMCAP.os_id 
    JOIN servicedescription   SD ON   SD.id   =   OS.svcdesc_id 
    JOIN orderedproduct    OP ON   OP.ordservice_id =   OS.id 
    JOIN productdescription   PROD ON  PROD.id   =   OP.proddesc_id_root 
    JOIN customerorder     CO ON   CO.id   =   OP.custorder_id 
    JOIN account      ACC ON  ACC.id   =   OP.account_id 
    JOIN contact      C ON   C.customer_id =  ACC.customer_id 
    JOIN address      ADDR ON  ADDR.id   =   C.address_id 
    JOIN contact      CON ON  CON.customer_id =  ACC.customer_id 
    JOIN address      AD ON   AD.id   =  CON.address_id 
WHERE PD.name IN ('County Code' , 'Service Occurrence' , 'VoIP Port' , 'VoIP MTA MAC address' , 'Primary TN' , 'HSDS CM MAC address' , 'VoIP FQDN' , 'Caller Id') 
    AND OSQ.current_value IS NOT NULL 
    AND SD.name in ('Voice over IP') 
    AND OP.resultingaction <> 2 
    AND OP.status = 10 
    AND ACC.status = 1 
    AND EXISTS (SELECT 1 
     FROM ORDEREDPRODUCT OP1 
     WHERE OP1.PRODUCT_ID = OP.PRODUCT_ID 
     AND OP1.STATUS = 10 
     HAVING MAX (OP1.ID) = OP.ID) 
    AND CO.ID IN (select ID 
     FROM CUSTOMERORDER CO1 
     where CO1.CUSTOMER_ID = ACC.CUSTOMER_ID 
     AND CO1.STATUS = 10) 
    AND NOT EXISTS (SELECT 1 
         FROM OSQUESTION OSQ2 
         , ORDEREDSERVICE OS1 
         , OSPARAMDATACAPABILITY OSPARAMCAP1 
         , OSQUESTIONGROUP OSQGRP1 
         , ORDEREDPRODUCT OP3 
        where OSQ2.EXT_QUEST_ID = PD.ID 
         AND OSQ2.QUESTION_ID > OSQ.QUESTION_ID 
         AND OSQ2.PROVISIONED_VALUE = OSQ.CURRENT_VALUE 
         AND OSQ2.CURRENT_VALUE != OSQ.CURRENT_VALUE 
         AND PD.NAME IN ('Primary TN' 
             , 'VoIP MTA MAC address' 
             , 'HSDS CM MAC address') 
         AND OSQGRP1.QG_ID = OSQ2.QG_ID 
         AND OSPARAMCAP1.CAP_ID = OSQGRP1.CAP_ID 
         AND OS1.ID = OSPARAMCAP1.OS_ID 
         AND OP.ROOTPRODUCT_ID = OP3.ROOTPRODUCT_ID 
         AND OP3.ORDSERVICE_ID = OS1.ID 
         AND OP3.STATUS = 10) 
ORDER BY ACC.EXTERNALBILLID 
     , OP.ROOTPRODUCT_ID 
     , CO.ID 

備註:

  • 要加入聯繫和地址兩次(這是無用的)。
  • 如果你想訂購帶有最大ID的產品,你可以使用半連接(你會發現其他問題)。
  • 檢查CO.ID對聯繫人表可以在JOIN部分完成。

我可以重寫第一部分爲:

SELECT ACC.id 
    , OP.rootprODUCT_ID 
    , ACC.externALBILLID 
    , CON.firstnAME 
    , CON.lastnaME 
    , AD.line1 
    , NVL (AD.line2 , '') AS  LINE2 
    , AD.towncity 
    , AD.state 
    , AD.postalzipcode 
    , PROD.billingcode 
    , PD.name    as  Prompt_Name 
    , OSQ.current_value 
    FROM promptdescription    PD 
    JOIN osquestion     OSQ ON  OSQ.ext_quest_id =   PD.id 
    JOIN osquestiongroup   OSQGRP ON  OSQGRP.qg_id   =  OSQ.qg_id 
    JOIN osparamdatacapability OSPARAMCAP ON OSPARAMCAP.cap_id  =  OSQGRP.cap_id 
    JOIN orderedservice    OS ON   OS.id   = OSPARAMCAP.os_id 
    JOIN servicedescription   SD ON   SD.id   =   OS.svcdesc_id 
    JOIN orderedproduct    OP ON   OP.ordservice_id =   OS.id 
    JOIN productdescription   PROD ON  PROD.id   =   OP.proddesc_id_root 
    JOIN account      ACC ON  ACC.id   =   OP.account_id 
    JOIN contact      C ON   C.customer_id =  ACC.customer_id 
    JOIN address      ADDR ON  ADDR.id   =   C.address_id 
    JOIN contact      CON ON  CON.customer_id =  ACC.customer_id 
    JOIN address      AD ON   AD.id   =  CON.address_id 
    JOIN customerorder     CO ON   CO.id   =   OP.custorder_id 
             AND   CO.customer_id =  ACC.customer_id 
    LEFT JOIN orderedproduct ismaxopid ON ismaxopid.product_id = op.product_id 
             AND ismaxopid.status = 10 
             AND ismaxopid.id > op.id 
WHERE PD.name IN ('County Code' , 'Service Occurrence' , 'VoIP Port' , 'VoIP MTA MAC address' , 'Primary TN' , 'HSDS CM MAC address' , 'VoIP FQDN' , 'Caller Id') 
    AND OSQ.current_value IS NOT NULL 
    AND SD.name in ('Voice over IP') 
    AND OP.resultingaction <> 2 
    AND OP.status = 10 
    AND ACC.status = 1 
    AND ismaxopid.id IS NULL 
    AND NOT EXISTS (SELECT 1 
         FROM OSQUESTION OSQ2 
         , ORDEREDSERVICE OS1 
         , OSPARAMDATACAPABILITY OSPARAMCAP1 
         , OSQUESTIONGROUP OSQGRP1 
         , ORDEREDPRODUCT OP3 
        where OSQ2.EXT_QUEST_ID = PD.ID 
         AND OSQ2.QUESTION_ID > OSQ.QUESTION_ID 
         AND OSQ2.PROVISIONED_VALUE = OSQ.CURRENT_VALUE 
         AND OSQ2.CURRENT_VALUE != OSQ.CURRENT_VALUE 
         AND PD.NAME IN ('Primary TN' 
             , 'VoIP MTA MAC address' 
             , 'HSDS CM MAC address') 
         AND OSQGRP1.QG_ID = OSQ2.QG_ID 
         AND OSPARAMCAP1.CAP_ID = OSQGRP1.CAP_ID 
         AND OS1.ID = OSPARAMCAP1.OS_ID 
         AND OP.ROOTPRODUCT_ID = OP3.ROOTPRODUCT_ID 
         AND OP3.ORDSERVICE_ID = OS1.ID 
         AND OP3.STATUS = 10) 
ORDER BY ACC.EXTERNALBILLID 
     , OP.ROOTPRODUCT_ID 
     , CO.ID 

的NOT EXISTS部分仍有待提高。

+0

OTOH可以將「LEFT JOIN orderedproduct ismaxopid ON ismaxopid.product_id」重寫爲「NOT EXISTS」子查詢,該子查詢至少減少外部選擇的範圍表。其他「不存在」的東西看起來像是外部查詢(可能爲了清楚而被壓縮成視圖)中的一部分的常見子表達式。 – wildplasser

+0

@wildplasser:我經歷過與非空檢查的左連接,大部分時間,導致更快的執行時間(我有一個查詢需要4秒,並重寫不存在的部分使它運行在3微秒)。 – Benoit

+0

我在這裏看到「LEFT JOIN + NULL check」的成語。它似乎是一個{oracle,mysql}的東西。在Postgres中,它們導致完全相同的查詢計劃。 「不存在」更清晰,更可讀,恕我直言。 MAX()也可以作爲一個集合來完成(+ - 集合的可空性) – wildplasser

0

首先識別查詢所有表中的所有PK字段。 然後根據oracle數據庫表中創建的PK字段的順序來更改where條件。