2016-02-29 2 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 TABLE

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) 

В то же время я пытаюсь использовать с пунктом для функций вызова, где положение, однако в процедуре есть функции, выловленной в постоянных переменных, которые затем используются в запросе!

Мои БД: Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Производство

Пожалуйста, обратитесь за дополнительной информацией в случае необходимости. Thanks

EDIT: Этот Процедура использует запрос и не написана мной! Я думаю, что сама эта процедура должна быть мелодия, кроме запроса

пожалуйста предложить

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 PLAN ПОСЛЕ СОЗДАНИЯ ДВУХ INDEXES -

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

Я обновляю квесто и добавляю процедуру, в которой этот запрос используется – mradul

+0

Можете ли вы уточнить: это _procedure_ или _query_, который занимает 4-5 часов? Если это процедура, то сколько времени занимает запрос? –

ответ

-1

Это немного длинно для комментария.

Ваш план и индексы запросов выглядят разумно. Это заставляет подозревать вызовы функций.

Ваши данные не выглядят невероятно большими. , , таблицы с несколькими миллионами строк. Мое подозрение в том, что их называют миллион раз. Люди, которые приходят из более традиционных языков программирования, часто считают, что функции - отличный способ программирования в SQL; к сожалению, они могут нести накладные расходы, поскольку они могут помешать оптимизатору выполнять свою работу.

Итак, можете ли объявить функции DETERMINISTIC? Это поможет оптимизатору скомпилировать их. Во-вторых, сохраните значения в списке NOT IN в CTE или, еще лучше, во временной таблице с индексом. Сделайте что-то подобное для значения PARM_ID.

+0

Я могу заменить эти функции на SQL-запросы, также если я использую эти функции в разделе с предложением, тогда это будет полезно здесь. Да, поскольку этот запрос не написан Я всегда старался избегать вызовов функций в SQL. Еще один вопрос, как узнать размер таблицы, посмотрев план Explain! – mradul

+0

@mradul ... Столбец «Строки» - это индикация ожидаемых данных том –

+0

Если я не ошибаюсь, но эти строки являются строками, возвращаемыми каждой операцией! – mradul

-1

Как это только SUB_SVC_ID вы хотите вернуться, вы можете получить его от SUB_SVC_PARM, где совпадает с SUB_SVC или SUB_SVC где SUB_SVC_PARM или объединением двух или от пересечения.Оптимизатор должен добраться до того же плана выполнения в любом случае, но вы все равно можете попробовать:

Ваш запрос (с IN вместо EXISTS, который ничего не меняет, но улучшить читаемость):

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

Я пробовал все альтернативы, которые вы предоставили, но не e из них помогают: (все дают ту же стоимость, однако опция пересечения увеличивает стоимость. Я думаю, мне нужно создать индекс на столбце sub-svc_status_id и удалить функцию, вызывающую из предложения where !! – mradul

+0

Хорошо, как уже упоминалось, оптимизатор * должен * производить тот же план, поэтому я не удивлен, что это не помогло. Это был небольшой шанс, не более того. Но вы добавили два индекса? Скорее всего, это ускорит запрос. –

+0

Да, я думал о том же, что мне нужно, чтобы получить разрешение на это, поскольку это домен на месте, и план объяснения тот же, даже когда я изменил функции с простым SQL-запросом и всеми альтернативами, которые вы предоставили! \ – mradul

Смежные вопросы