Оптимизировать запросы вложенных циклов в Oracle - PullRequest
0 голосов
/ 17 марта 2019

Я создал запрос Oracle, позже мне нужно интегрировать в процедуру.

В моем блоке SQL у меня есть два таких вложенных цикла (операторы Select работают нормально):

DECLARE
  m_card_no NUMBER;
BEGIN
  FOR i IN (SELECT DISTINCT VISA_NUMBER FROM LC.WEEKLY_ROP_CARD_A WHERE NOT EXISTS (SELECT 1 FROM LC.LCT_MOMP_ROP WHERE VISA_NO = VISA_NUMBER))
  LOOP
    FOR n IN (
      SELECT DISTINCT l.new_clearance_no, l.occupation_code, l.sex_code, rtrim(ltrim(a.civil_number)) civil_number, a.name_e, a.name_a, a.date_of_birth, a.passport_number, a.passport_issue_country_code, a.passort_issue_date, a.passort_expiry_date, a.nationality_code, lpad(rtrim(ltrim(a.visa_number)),8,0) visa_number, a.visa_issue_date, a.visa_expiry_date, v.lct_occupation_clear_id, DECODE(V.LCM_VISA_APPL_TYPE_ID,7,'LOCAL ENDORSEMENT','ARRIVAL') TRAN
      FROM WEEKLY_ROP_CARD_A A
      JOIN LCT_OCCUPATION_CLEAR L ON L.OCCUPATION_CODE = A.OCCUPATION_CODE
      JOIN LCT_APPL_VISA V ON V.LCT_OCCUPATION_CLEAR_ID = L.ID
      where lpad(v.visa_no,8,0)=lpad(rtrim(ltrim(a.visa_number)),8,0) and v.lct_occupation_clear_id=l.id and a.last_mov_type='IN' AND ( LCM_VISA_APPL_TYPE_ID <> 6 or LCM_VISA_APPL_TYPE_ID is null) and lpad(v.visa_no,8,0)=i.VISA_NUMBER
    )
    LOOP
        --INSERT QUERY TO ANOTHER TABLE HERE
    END LOOP;
  END LOOP;
END;

Запрос в первом цикле FOR содержит более 1,6 миллиона записей, а во втором цикле - более 600 000 записей. Когда я запускаю оба запроса по отдельности, это дает результат, поэтому в запросе нет ошибок. Но когда я запускаю вышеуказанный блок, он даже не достигает оператора вставки. Есть ли способ вставить записи без проблем?

Ответы [ 2 ]

1 голос
/ 17 марта 2019

Прежде всего, оператор INSERT INTO ... SELECT FROM на основе множеств будет намного быстрее, чем однострочный оператор INSERT INTO ... VALUES внутри цикла.

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

Собираем этот совет вместе ...

insert into your_table 
      SELECT DISTINCT l.new_clearance_no, 
             l.occupation_code, 
             l.sex_code, 
             rtrim(ltrim(a.civil_number)) civil_number,
             a.name_e, 
             a.name_a, 
             a.date_of_birth,
             a.passport_number, 
             a.passport_issue_country_code, 
             a.passort_issue_date, 
             a.passort_expiry_date, 
             a.nationality_code, 
             lpad(rtrim(ltrim(a.visa_number)),8,0) visa_number, 
             a.visa_issue_date, 
             a.visa_expiry_date, 
             v.lct_occupation_clear_id, 
             DECODE(V.LCM_VISA_APPL_TYPE_ID,7,'LOCAL ENDORSEMENT','ARRIVAL') TRAN
      FROM WEEKLY_ROP_CARD_A A
      JOIN LCT_OCCUPATION_CLEAR L ON L.OCCUPATION_CODE = A.OCCUPATION_CODE
      JOIN LCT_APPL_VISA V ON V.LCT_OCCUPATION_CLEAR_ID = L.ID
      where lpad(v.visa_no,8,0)=lpad(rtrim(ltrim(a.visa_number)),8,0) 
      and v.lct_occupation_clear_id=l.id 
      and a.last_mov_type='IN' 
      AND ( LCM_VISA_APPL_TYPE_ID <> 6 or LCM_VISA_APPL_TYPE_ID is null) 
      and lpad(v.visa_no,8,0)=i.VISA_NUMBER
      and NOT EXISTS (SELECT 1 FROM LC.LCT_MOMP_ROP WHERE VISA_NO = a.VISA_NUMBER)
;

Кроме того, если значение LC.LCT_MOMP_ROP.VISA_NO равно , гарантированно равно not null, вы можете проверить, является ли NOT IN более производительным, чем NOT EXISTS.

0 голосов
/ 18 марта 2019

Вся заслуга APC за то, что он набрался терпения переписать его.
Если это займет слишком много времени, вы можете попробовать версию ниже и заглянуть в план выполнения для ожидания и некоторых подсказок, подобных приведенным ниже ... не вседлинные запросы вызваны тем, что dba:

-PQ_DISTRIBUTE (для секционированных таблиц)

-LEADING

-PRECOMPUTE_SUBQUERY (для подзапросов)

-USE_HASH

-FULL

   insert /*+ append parallel(aaa,8) */ into your_table aaa
          SELECT /*+ parallel(A,4) parallel(L,4) parallel(V,4) */DISTINCT l.new_clearance_no, 
                 l.occupation_code, 
                 l.sex_code, 
                 rtrim(ltrim(a.civil_number)) civil_number,
                 a.name_e, 
                 a.name_a, 
                 a.date_of_birth,
                 a.passport_number, 
                 a.passport_issue_country_code, 
                 a.passort_issue_date, 
                 a.passort_expiry_date, 
                 a.nationality_code, 
                 lpad(rtrim(ltrim(a.visa_number)),8,0) visa_number, 
                 a.visa_issue_date, 
                 a.visa_expiry_date, 
                 v.lct_occupation_clear_id, 
                 DECODE(V.LCM_VISA_APPL_TYPE_ID,7,'LOCAL ENDORSEMENT','ARRIVAL') TRAN
          FROM WEEKLY_ROP_CARD_A A
          JOIN LCT_OCCUPATION_CLEAR L ON L.OCCUPATION_CODE = A.OCCUPATION_CODE
          JOIN LCT_APPL_VISA V ON V.LCT_OCCUPATION_CLEAR_ID = L.ID
          where lpad(v.visa_no,8,0)=lpad(rtrim(ltrim(a.visa_number)),8,0) 
          and v.lct_occupation_clear_id=l.id 
          and a.last_mov_type='IN' 
          AND ( LCM_VISA_APPL_TYPE_ID <> 6 or LCM_VISA_APPL_TYPE_ID is null) 
          and lpad(v.visa_no,8,0)=i.VISA_NUMBER
          and NOT EXISTS (SELECT 1 FROM LC.LCT_MOMP_ROP WHERE VISA_NO = a.VISA_NUMBER)
...