在Oracle中优化嵌套循环查询

时间:2019-03-17 09:59:40

标签: oracle performance plsql query-optimization

我创建了一个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循环中的查询有160万条记录,第二个循环中有60万条记录。当我分别运行两个查询时,它提供结果,因此查询中没有任何错误。但是当我运行上面的代码块时,它甚至没有到达插入语句。有没有办法插入记录而没有任何问题?

2 个答案:

答案 0 :(得分:1)

首先,基于一个集合的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具有更高的性能。

答案 1 :(得分:0)

所有信用归功于APC的耐心重写。
如果花费的时间太长,您可以尝试使用以下版本,并查看执行计划中的等待内容和一些类似于以下内容的提示...并非所有冗长的查询都是因为dba:

-PQ_DISTRIBUTE(用于分区表)

-领先

-PRECOMPUTE_SUBQUERY(用于子查询)

-USE_HASH

-满

   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)