2016-02-29 136 views
0

我有這個查詢是一個性能調整的候選人,因爲它需要超過4-5小時運行。性能調整sql查詢

explain plan for SELECT /*+ PARALLEL_INDEX(ssp, sub_svc_parm_ix2, 4) 
          INDEX(ssp sub_svc_parm_ix2) */ 
      SUB_SVC_ID 
     FROM SUB_SVC_PARM ssp 
     WHERE PARM_ID = GET_PARM_ID('net_ppv_credit_limit', GET_CLASS_ID('SubSvcSpec'), GET_SVCID('smp_cpe_cas')) 
     AND VAL <> '140.00' 
     AND EXISTS (SELECT /*+ PARALLEL_INDEX(ss, sub_svc_pk, 4) */ 
          1 
         FROM SUB_SVC ss 
         WHERE ss.SUB_SVC_ID = ssp.SUB_SVC_ID 
         AND ss.SUB_SVC_STATUS_ID NOT IN (FN_GET_STATUS_ID('SubSvcSpec', 'deleted'), 
                 FN_GET_STATUS_ID('SubSvcSpec', 'inactive'), 
                 FN_GET_STATUS_ID('SubSvcSpec', 'add_in_progress'), 
                 FN_GET_STATUS_ID('SubSvcSpec', 'activation_in_progress'), 
                 FN_GET_STATUS_ID('SubSvcSpec', 'courtesy_block_in_progress'), 
                 FN_GET_STATUS_ID('SubSvcSpec', 'mso_block_in_progress'), 
                 FN_GET_STATUS_ID('SubSvcSpec', 'delete_in_progress'), 
                 FN_GET_STATUS_ID('SubSvcSpec', 'deactivation_in_progress'), 
                 FN_GET_STATUS_ID('SubSvcSpec', 'change_in_progress'))); 

我在這裏發佈被稱爲過程中的遊標的原始查詢。

解釋計劃在它需要時間域的查詢 -

Plan hash value: 4290343623 

----------------------------------------------------------------------------   -----------------------------   
    | Id | Operation     | Name    | Rows | Bytes  |TempSpc| Cost (%CPU)| Time  | 
--------------------------------------------------------------------------- ------------------------------ 
| 0 | SELECT STATEMENT    |     | 1802K| 56M|  | 528K (1)|730:11:02 | 
|* 1 | HASH JOIN RIGHT SEMI  |     | 1802K| 56M| 37M| 528K (1)|730:11:02 | 
|* 2 | TABLE ACCESS FULL   | SUB_SVC   | 1763K| 16M|  | 311K (1)|430:15:33 | 
| 3 | TABLE ACCESS BY INDEX ROWID| SUB_SVC_PARM  | 2394K| 52M|  | 209K (0)|288:56:00 | 
|* 4 | INDEX RANGE SCAN   | SUB_SVC_PARM_IX2 | 2394K|  |  | 1519 (0)| 02:05:59 | 
--------------------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

1 - access("SS"."SUB_SVC_ID"="SSP"."SUB_SVC_ID") 
2 - filter("SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','deleted') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','inactive') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','add_in_progress') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','activation_in_progress') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','courtesy_block_in_progress') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','mso_block_in_progress') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','delete_in_progress') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','deactivation_in_progress') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','change_in_progress')) 
4 - access("PARM_ID"="GET_PARM_ID"('net_ppv_credit_limit',"GET_CLASS_ID"('SubSvcSpec'),"GET_SV 
      CID"('smp_cpe_cas'))) 
    filter("VAL"<>'140.00') 

索引建立兩個表上都---

SUB_SVC表

index_name  coulmn_name 
-----------  ------------ 
SUB_SVC_PK  sub_svc_id 
SUB_SVC_IX4  PARENT_SUB_SVC_ID 
SUB_SVC_IX5  EXTERNAL_KEY 
SUB_SVC_IX6  SUB_SVC_IX6 

SUB_SVC_PARM表

index_name  coulmn_name 
-----------  ------------ 
SUB_SVC_PARM_PK SUB_SVC_ID, PARM_ID 
SUB_SVC_PARM_IX2 PARM_ID, VAL 

CREATE TABLE語法SUB_SVC_PARM表

CREATE TABLE "SMPHOMCM"."SUB_SVC_PARM" 
    ( "SUB_SVC_ID" NUMBER(12,0) NOT NULL ENABLE, 
"PARM_ID" NUMBER(12,0) NOT NULL ENABLE, 
"VAL" VARCHAR2(2000 BYTE) NOT NULL ENABLE, 
CONSTRAINT "SUB_SVC_PARM_PK" PRIMARY KEY ("SUB_SVC_ID", "PARM_ID") 
    USING INDEX) 

CREATE TABLE SYNTAX FOR SUB_SVC TABLE 

CREATE TABLE "SMPHOMCM"."SUB_SVC" 
    ( "SUB_SVC_ID" NUMBER(12,0) NOT NULL ENABLE, 
"SUB_ID" NUMBER(12,0) NOT NULL ENABLE, 
"START_DT" DATE NOT NULL ENABLE, 
"EXTERNAL_KEY" VARCHAR2(100 BYTE) NOT NULL ENABLE, 
"SAMP_VER" NUMBER(9,0) NOT NULL ENABLE, 
"SUB_SVC_STATUS_ID" NUMBER(12,0) NOT NULL ENABLE, 
"CREATED_DTM" DATE NOT NULL ENABLE, 
"CREATED_BY" VARCHAR2(30 BYTE) NOT NULL ENABLE, 
"END_DT" DATE, 
"PURCHASE_DT" DATE, 
"PARENT_SUB_SVC_ID" NUMBER(12,0), 
"PRE_STATUS_ID" NUMBER(12,0), 
"MODIFIED_DTM" DATE, 
"MODIFIED_BY" VARCHAR2(30 BYTE), 
"SVC_ID" NUMBER(12,0), 
CONSTRAINT "SUB_SVC_PK" PRIMARY KEY ("SUB_SVC_ID") 
USING INDEX) 

同時我試圖憑藉對功能子句中使用的方法有功能都陷入了不斷的變量,然後在查詢中使用但調用where子句!

我的DB是:Oracle數據庫11g企業版發佈11.2.0.2.0 - 64位生產

如果需要,請索取更多信息。 謝謝

編輯:此過程使用查詢,不是由我寫的! 我覺得這個過程本身需要比查詢

其他調請建議

CREATE OR REPLACE PROCEDURE PPV_CREDIT_LIMIT(p_exid NUMBER) 
IS 
-- Flag 'N' is null 

    TYPE tab_sub_svc_id    IS TABLE OF SUB_SVC_PARM.SUB_SVC_ID%TYPE INDEX BY PLS_INTEGER; 
    rs_sub_svc_id      tab_sub_svc_id; 

    c_class_SubSvcSpec    constant pls_integer := GET_CLASS_ID('SubSvcSpec'); 
    c_svc_smp_cpe_cas     constant pls_integer := GET_SVCID('smp_cpe_cas'); 
    c_parm_net_ppv_credit_limit  constant pls_integer := GET_PARM_ID('net_ppv_credit_limit', c_class_SubSvcSpec, c_svc_smp_cpe_cas); 
    c_deleted       constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'deleted'); 
    c_inactive      constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'inactive'); 
    c_add_in_progress     constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'add_in_progress'); 
    c_activation_in_progress   constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'activation_in_progress'); 
    c_courtesy_block_in_progress  constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'courtesy_block_in_progress'); 
    c_mso_block_in_progress   constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'mso_block_in_progress'); 
    c_delete_in_progress    constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'delete_in_progress'); 
    c_deactivation_in_progress  constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'deactivation_in_progress'); 
    c_change_in_progress    constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'change_in_progress'); 
    c_ppv_credit_limit    constant varchar2(6) := '140.00'; 
    -- Added for net_creditthreshold parm 
    c_parm_ppv_credit_threshold  constant pls_integer := GET_PARM_ID('net_ppv_creditthreshold', c_class_SubSvcSpec, c_svc_smp_cpe_cas); 
    c_ppv_credit_threshold   constant varchar2(6) := '80.00'; 
    ilimit       CONSTANT PLS_INTEGER := 1000; 
    iCheck       CONSTANT PLS_INTEGER := 10; 
    l_total_recs        PLS_INTEGER; 
    l_rec_cnt         PLS_INTEGER; 
    l_curr_cnt         PLS_INTEGER := 0; 
    l_batch         PLS_INTEGER := 0; 
    v_stop_flag        CHAR(1) := 'N'; 

    cursor curPPV_CL IS 
     SELECT /*+ PARALLEL_INDEX(ssp, sub_svc_parm_ix2, 4) 
          INDEX(ssp sub_svc_parm_ix2) */ 
      SUB_SVC_ID 
     FROM SUB_SVC_PARM ssp 
     WHERE PARM_ID = c_parm_net_ppv_credit_limit 
     AND VAL <> '140.00' 
     AND EXISTS (SELECT /*+ PARALLEL_INDEX(ss, sub_svc_pk, 4) */ 
          1 
         FROM SUB_SVC ss 
         WHERE ss.SUB_SVC_ID = ssp.SUB_SVC_ID 
         AND ss.SUB_SVC_STATUS_ID NOT IN (c_deleted, 
                 c_inactive, 
                 c_add_in_progress, 
                 c_activation_in_progress, 
                 c_courtesy_block_in_progress, 
                 c_mso_block_in_progress, 
                 c_delete_in_progress, 
                 c_deactivation_in_progress, 
                 c_change_in_progress)); 

BEGIN 

    DBMS_APPLICATION_INFO.set_action (NULL); 
    DBMS_APPLICATION_INFO.set_module (NULL, NULL); 
    DBMS_APPLICATION_INFO.set_client_info (NULL); 

    DBMS_APPLICATION_INFO.set_module (module_name => 'Procedure: PPV_CREDIT_LIMIT', 
           action_name => 'Counting total updatable records'); 

    SELECT /*+ PARALLEL_INDEX(ssp, sub_svc_parm_ix2, 4) 
        INDEX(ssp sub_svc_parm_ix2) */ 
     COUNT(SUB_SVC_ID) 
INTO l_total_recs 
FROM SUB_SVC_PARM ssp 
WHERE PARM_ID = c_parm_net_ppv_credit_limit 
    AND VAL <> '140.00' 
    AND EXISTS (SELECT /*+ PARALLEL_INDEX(ss, sub_svc_pk, 4) */ 
        1 
       FROM SUB_SVC ss 
       WHERE ss.SUB_SVC_ID = ssp.SUB_SVC_ID 
       AND ss.SUB_SVC_STATUS_ID NOT IN (c_deleted, 
                c_inactive, 
                c_add_in_progress, 
                c_activation_in_progress, 
                c_courtesy_block_in_progress, 
                c_mso_block_in_progress, 
                c_delete_in_progress, 
                c_deactivation_in_progress, 
                c_change_in_progress)); 

    DBMS_OUTPUT.PUT_LINE('Total records for updating are : ' || l_total_recs); 

    OPEN curPPV_CL; 

    LOOP 
     FETCH curPPV_CL 
     BULK COLLECT INTO rs_sub_svc_id limit ilimit; 

     l_rec_cnt := rs_sub_svc_id.COUNT; 
     l_curr_cnt := l_curr_cnt + l_rec_cnt; 

     DBMS_APPLICATION_INFO.set_module (module_name => 'Procedure: PPV_CREDIT_LIMIT', 
            action_name => 'Updating ' || l_curr_cnt || ' of ' || l_total_recs); 

     for idx in 1 .. l_rec_cnt 
     LOOP 
      UPDATE SUB_SVC_PARM 
     SET VAL = c_ppv_credit_limit 
     WHERE SUB_SVC_ID = rs_sub_svc_id(idx) 
     AND PARM_ID = c_parm_net_ppv_credit_limit; 

     UPDATE SUB_SVC_PARM 
     SET VAL = c_ppv_credit_threshold 
     WHERE SUB_SVC_ID = rs_sub_svc_id(idx) 
     AND PARM_ID = c_parm_ppv_credit_threshold; 

    END LOOP; 
    COMMIT; 


    l_batch := l_batch + 1; 
    DBMS_APPLICATION_INFO.set_client_info ('BATCH:' || l_batch * ilimit); 
    EXIT WHEN l_rec_cnt < ilimit; 

    IF MOD(l_batch, iCheck) = 0 
    THEN 
     SELECT STOP_FLAG 
      INTO v_stop_flag 
      FROM DM_PPV_CREDIT_LIMIT 
     WHERE EXECUTION_ID = p_exid; 
    END IF; 

    EXIT WHEN v_stop_flag = 'Y'; 

    END LOOP; 

    CLOSE curPPV_CL; 

DBMS_OUTPUT.PUT_LINE('Have updated records : ' || l_curr_cnt || ' out of total records : ' || l_total_recs ); 

EXCEPTION 
    WHEN OTHERS THEN 
     DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM); 
END PPV_CREDIT_LIMIT; 

EXPLAIN計劃之後創建了兩個指標 -

create index sub_svc_parm_ixpvs on sub_svc_parm (parm_id, val, sub_svc_id) ; 

create index sub_svc_ixss on sub_svc (sub_svc_id, sub_svc_status_id) TABLESPACE "SMP_IDX_SUB_SVC" ; 


Plan hash value: 176576580 

----------------------------------------------------------------------------  -------------------- 
| Id | Operation   | Name    | Rows | Bytes |TempSpc| Cost (%CPU)| Time  | 
---------------------------------------------------------------------------- -------------------- 
| 0 | SELECT STATEMENT |     | 1802K| 56M|  | 43296 (1)| 59:49:34 | 
|* 1 | HASH JOIN  |     | 1802K| 56M| 37M| 43296 (1)| 59:49:34 | 
|* 2 | INDEX FULL SCAN | SUB_SVC_IXSS  | 1763K| 16M|  | 33679 (1)| 46:32:15 | 
|* 3 | INDEX RANGE SCAN| SUB_SVC_PARM_IXPVS | 2308K| 50M|  | 1857 (0)| 02:34:00 | 
------------------------------------------------------------------------------------------------ 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - access("SS"."SUB_SVC_ID"="SSP"."SUB_SVC_ID") 
    2 - filter("SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','deleted') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','inactive') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','add_in_progress') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','activation_in_progress') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','courtesy_block_in_progress') 
      AND "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','mso_block_in_progress') 
      AND "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','delete_in_progress') AND 
      "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','deactivation_in_progress') 
      AND "SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','change_in_progress')) 
    3 - access("SSP"."PARM_ID"="GET_PARM_ID"('net_ppv_credit_limit',"GET_CLASS_ID"('SubSv 
      cSpec'),"GET_SVCID"('smp_cpe_cas'))) 
    filter("SSP"."VAL"<>'140.00') 
+0

它用在遊標中。 Ca you clairfy:當你在遊標中運行你提供的查詢_not_是否需要那麼長時間? –

+0

我正在更新questio並在使用此查詢的位置添加過程 – mradul

+0

您能否澄清:是否需要4-5小時的_procedure_或_query_?如果是程序,那麼查詢需要多長時間? –

回答

-1

這是很長的評論了一下。

您的查詢計劃和索引看起來很合理。這導致人們懷疑函數調用。

您的數據看起來並不是很大。 。 。有幾百萬行的表格。我的懷疑是這些被稱爲數十億次。來自更傳統編程語言的人們通常認爲函數是用SQL進行編程的好方法;不幸的是,它們可能會產生很多開銷,因爲它們會阻止優化器的工作。

那麼,你可以聲明的功能是DETERMINISTIC?這將有助於優化器編譯它們。其次,將值存儲在CTE中的NOT IN列表中,或者更好的是將其存儲在具有索引的臨時表中。對PARM_ID值做類似的操作。

+0

我可以用SQL查詢替換這些函數,如果我在with子句中使用這些函數,那麼它會在這裏有所幫助,因爲這些查詢沒有被寫入通過我,我總是試圖避免SQL中的函數調用,還有一個問題是通過查看解釋計劃來了解表的大小! – mradul

+0

@mradul ...「行」列是預期數據的指示量 –

+0

如果我沒有錯,但這些行是每個操作返回的行! – mradul

-1

因爲它只是您要返回的SUB_SVC_ID,所以您可以從SUB_SVC_PARM(其中SUB_SVC匹配)或從SUB_SVC(其中SUB_SVC_PARM或來自兩者的連接或來自交叉點)中獲取它。優化應該得到在任何情況下相同的執行計劃,但你仍然可以嘗試:

您的查詢(用,而不是存在,這不會改變任何東西,但增強可讀性):

select sub_svc_id 
from sub_svc_parm 
where parm_id = get_parm_id(...) 
and val <> '140.00' 
and sub_svc_id in (select sub_svc_id from sub_svc where sub_svc_status_id not in (...)); 

備選#1:

select sub_svc_id 
from sub_svc 
where sub_svc_status_id not in (...) 
and sub_svc_id in 
    (select * from sub_svc_parm where parm_id = get_parm_id(...) and val <> '140.00'); 

備選#2:

select sub_svc_id 
from sub_svc ss 
join sub_svc_parm ssp using (sub_svc_id) 
where ss.sub_svc_status_id not in (...) 
and ssp.parm_id = get_parm_id(...) 
and ssp.val <> '140.00'); 

替代#3:

select sub_svc_id 
from sub_svc_parm 
where parm_id = get_parm_id(...) 
and val <> '140.00' 
intersect 
select sub_svc_id 
from sub_svc 
where sub_svc_status_id not in (...)); 

在任何情況下,指標最好應爲:sub_svc_parm(parm_id, val, sub_svc_id)sub_svc(sub_svc_status_id, sub_svc_id)。添加這些可能已經加速了現有的查詢。

我會先嚐試一下沒有任何提示,看看優化器爲這些查詢產生了什麼執行計劃。然後你可能想再次添加並行化提示。

+0

我嘗試了所有你提供的替代方案,但不是他們幫助:(所有提供相同的費用,但交叉選項增加成本。我想我需要在sub-svc_status_id列上創建一個索引,並從where子句中刪除函數調用! – mradul

+0

好的,如上所述,優化器*應該*產生相同的計劃,所以我並不感到驚訝,它沒有幫助。這只是一個微不足道的機會,沒有更多。但是你添加了兩個索引嗎?這很可能會加快查詢速度。 –

+0

是啊我想同樣我需要採取這一權限,因爲它是一個現場域和解釋計劃是相同的,即使當我改變了簡單的SQL查詢功能和您提供的所有替代品\ – mradul