Oracle:使用变量时删除语句变得非常慢

问题描述 投票:0回答:0

我有一个通常需要大约 5 分钟才能运行的 Oracle 过程。过程中有两个区域需要查询可能已被修改的 ID 号列表。这两个段中的查询是相同的。第一个在游标定义的开头,第二个在过程主体的 delete 语句中。经常重复的关键部分涉及获取刷新某个表的最新日期。整个过程相当冗长,所以我只在下面包含相关部分。

这里是光标的开头:

cursor gvg_profile_c is
     
with last_refreshed as
  (select trunc(max(t.last_refreshed)) as max_date
     from ad.pbi_gvg_profile t),
      
with modified_ids as
 (
        
  select distinct id_number
    from ad.hr_giving cg
    join ad.pbi_dates d
      on d.DATE_FULL = trunc(cg.processed_date)
   where d.RELATIVE_DATE >= (select max_date from last_refreshed)
     and d.RELATIVE_DATE <= trunc(CURRENT_DATE)
     and cg.fiscal_year >= ad.current_fiscal_year - 6
        
  union
        
  select distinct gi.gift_donor_id as id_number
    from ad.gift gi
   where gi.date_added >= (select max_date from last_refreshed)
      or gi.date_modified >= (select max_date from last_refreshed)
        
  union
        
  select distinct p.pledge_donor_id as id_number
    from ad.pledge_rev p
   where p.date_added >= (select max_date from last_refreshed)
      or p.date_modified >= (select max_date from last_refreshed)
        
  union
        
  select distinct a.id_number
    from ad.affiliation a
   where a.date_added >= (select max_date from last_refreshed)
      or a.date_modified >= (select max_date from last_refreshed)
        
  ),

这里是删除语句:

delete from ad.pbi_gvg_profile p
  where p.id_number in
        (with last_refreshed as (select trunc(max(t.last_refreshed)) as max_date
            from ad.pbi_gvg_profile t)
          select distinct id_number
            from ad.hr_giving cg
            join ad.pbi_dates d
              on d.DATE_FULL = trunc(cg.processed_date)
           where d.RELATIVE_DATE >= (select max_date from last_refreshed)
             and d.RELATIVE_DATE <= trunc(CURRENT_DATE)
             and cg.fiscal_year >= ad.current_fiscal_year - 6
          
          union
          
          select distinct gi.gift_donor_id as id_number
            from ad.gift gi
           where gi.date_added >= (select max_date from last_refreshed)
              or gi.date_modified >= (select max_date from last_refreshed)
          
          union
          
          select distinct p.pledge_donor_id as id_number
            from ad.pledge_rev p
           where p.date_added >= (select max_date from last_refreshed)
              or p.date_modified >= (select max_date from last_refreshed)
          
          union
          
          select distinct a.id_number
            from ad.affiliation a
           where a.date_added >= (select max_date from last_refreshed)
              or a.date_modified >= (select max_date from last_refreshed)
         );

我认为拥有一个计算 last_refreshed 日期并将其放入可重复使用的变量中的函数会更有意义并且更有效。所以我就那样做了。这是功能:

注意:你可以在这里看到我有时需要从不同的表中获取日期。这是通过 if/else 解释了上面的代码,我只是把它省略了,所以你不必阅读相同的代码 4 次。

  function get_last_refreshed_date(scope in smallint) return date is
    
  last_refreshed date;
  table_name varchar2(30);
  select_sql varchar2(255);
  
  begin

  if scope = c_scope_all then
    table_name := 'ad.pbi_gvg_profile';
  else
    table_name := 'ad.pbi_gvg_profile_ag';
  end if;
  select_sql := 'select trunc(max(last_refreshed))
                 from '||table_name;
         
                 
  execute immediate select_sql 
  into last_refreshed;

  
  return(last_refreshed);
  
  end get_last_refreshed_date;

然后我改变光标的开头来使用这个函数和一个变量,所以现在它看起来像这样:

last_refreshed  date := get_last_refreshed_date(scope);

cursor gvg_profile_c is

with modified_ids as
 (
        
  select distinct id_number
    from ad.hr_giving cg
    join ad.pbi_dates d
      on d.DATE_FULL = trunc(cg.processed_date)
   where d.RELATIVE_DATE >= last_refreshed
     and d.RELATIVE_DATE <= trunc(CURRENT_DATE)
     and cg.fiscal_year >= ad.current_fiscal_year - 6
        
  union
        
  select distinct gi.gift_donor_id as id_number
    from ad.gift gi
   where gi.date_added >= last_refreshed
      or gi.date_modified >= last_refreshed
        
  union
        
  select distinct p.pledge_donor_id as id_number
    from ad.pledge_rev p
   where p.date_added >= last_refreshed
      or p.date_modified >= last_refreshed
        
  union
        
  select distinct a.id_number
    from ad.affiliation a
   where a.date_added >= last_refreshed
      or a.date_modified >= last_refreshed
        
  ),

这很好用。我的程序仍然只需要 5 分钟即可运行。

但是,当我对 Delete 语句进行相同的更改时,程序突然需要大约 65 分钟才能运行。从日志中我可以看出,删除语句的执行占了其中 60 多分钟。

为什么变量在游标中可以正常工作,但会导致过程主体中的 delete 语句严重变慢?

非常感谢任何帮助!

sql oracle stored-procedures oracle12c
© www.soinside.com 2019 - 2024. All rights reserved.