【问题标题】:Optimize nested loop queries in Oracle优化 Oracle 中的嵌套循环查询
【发布时间】:2019-08-07 21:45:35
【问题描述】:

我已经创建了一个 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 万条记录,第二个循环有超过 600,000 条记录。当我分别运行这两个查询时,它会提供结果,因此查询中没有任何错误。但是当我运行上面的块时,它甚至没有达到插入语句。有什么方法可以毫无问题地插入记录吗?

【问题讨论】:

  • 不要使用循环。使用单个 insert into .. select .. 语句
  • 由于我是 oracle 新手,请您创建一个示例并展示一下

标签: oracle performance plsql query-optimization


【解决方案1】:

所有功劳都归功于 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)

【讨论】:

    【解决方案2】:

    首先,基于集合的 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 更具执行性。

    【讨论】:

    • 这个查询看起来不错,但根据我当前的数据结构,我有超过 400,000 条记录要插入。 INSERT INTO 语句会毫无问题地执行吗?
    • 是的,只要您的 DBA 在配置方面做得很好。
    猜你喜欢
    • 1970-01-01
    • 2021-01-21
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-30
    • 1970-01-01
    相关资源
    最近更新 更多