合并语句导致 oracle 出现性能问题

问题描述

我正在尝试使用 oracle 中的合并语句进行更新,源有 20M 条记录,目标有 118 M 条记录。合并的执行需要很长时间。下面列出的是我的合并声明。我还放置了解释计划的屏幕截图以供参考。

enter image description here

MERGE
/*+ parallel(A,10) enable_parallel_dml*/
INTO
(
  SELECT
    PAY_RANGE_START_DATE_KEY,AA_PERSON_NATURAL_KEY,AA_PERSON_ASSIGNMENT_KEY,SCHEDULE_LINE_ID,SRC_CREATED_DATE,SRC_LAST_UPDATE_DATE
  FROM
    EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP
)
A USING
(
  SELECT
    pay_range_start_date_key,aa_person_natural_key,aa_person_assignment_key,schedule_line_id,MAX(src_created_date) src_created_date,MAX(src_last_update_date) src_last_update_date
  FROM
    edwfin.psp_labor_schd_day_f_rollup_frs_356
  GROUP BY
    pay_range_start_date_key,schedule_line_id
)
B ON
(
  A.PAY_RANGE_START_DATE_KEY = B.PAY_RANGE_START_DATE_KEY AND
  A.AA_PERSON_NATURAL_KEY    = B.AA_PERSON_NATURAL_KEY AND
  A.AA_PERSON_ASSIGNMENT_KEY = B.AA_PERSON_ASSIGNMENT_KEY AND
  A.SCHEDULE_LINE_ID         = B.SCHEDULE_LINE_ID
)
WHEN MATCHED THEN
  UPDATE
  SET
    A.SRC_CREATED_DATE     = B.SRC_CREATED_DATE,A.SRC_LAST_UPDATE_DATE = B.SRC_LAST_UPDATE_DATE
  WHERE
    A.SRC_CREATED_DATE      <> B.SRC_CREATED_DATE
  OR A.SRC_LAST_UPDATE_DATE <> B.SRC_LAST_UPDATE_DATE;
  COMMIT; 

解决方法

如果这是一次性交易,我会简单地使用 CTAS 或 Insert... 作为 select... 重新创建表,然后再添加索引。您已经在使用并行执行; CTAS 或 Insert ... as select... 可以做直接路径。

select 语句看起来像这样。我还假设所有键列都定义为 NOT NULL。

select < all columns from A,except SRC_CREATED_DATE and SRC_LAST_UPDATE_DATE >,case 
        when B.PAY_RANGE_START_DATE_KEY is null 
          then A.SRC_CREATED_DATE
          else 
            case
              when     A.SRC_CREATED_DATE <> B.SRC_CREATED_DATE OR A.SRC_LAST_UPDATE_DATE <> B.SRC_LAST_UPDATE_DATE 
                then B.SRC_CREATED_DATE
                else A.SRC_CREATED_DATE
              end
        end SRC_CREATED_DATE,case 
        when B.PAY_RANGE_START_DATE_KEY is null 
          then A.SRC_LAST_UPDATE_DATE
          else 
            case
              when     A.SRC_CREATED_DATE <> B.SRC_CREATED_DATE OR A.SRC_LAST_UPDATE_DATE <> B.SRC_LAST_UPDATE_DATE 
                then B.SRC_LAST_UPDATE_DATE
                else A.SRC_LAST_UPDATE_DATE
              end
        end SRC_LAST_UPDATE_DATE
     from EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP  A  
left join (  SELECT
    pay_range_start_date_key,aa_person_natural_key,aa_person_assignment_key,schedule_line_id,MAX(src_created_date) src_created_date,MAX(src_last_update_date) src_last_update_date
  FROM
    edwfin.psp_labor_schd_day_f_rollup_frs_356
  GROUP BY
    pay_range_start_date_key,schedule_line_id
    ) B
on   A.PAY_RANGE_START_DATE_KEY = B.PAY_RANGE_START_DATE_KEY AND
     A.AA_PERSON_NATURAL_KEY    = B.AA_PERSON_NATURAL_KEY AND
     A.AA_PERSON_ASSIGNMENT_KEY = B.AA_PERSON_ASSIGNMENT_KEY AND
     A.SCHEDULE_LINE_ID         = B.SCHEDULE_LINE_ID