Oracle Merge Statements的性能问题,记录超过200万条

时间:2014-02-10 05:17:44

标签: performance oracle merge

我正在为插入更新操作执行以下MERGE语句。

它可以处理100到200万条记录,但是对于超过4到50亿条记录,需要6到7个小时才能完成。

任何人都可以为合并声明提供一些替代或性能提示

 merge into employee_payment ep
  using (
     select
        p.pay_id vista_payroll_id,
        p.pay_date pay_dte,
        c.client_id client_id,
        c.company_id company_id,
        case p.uni_ni when 0 then null else u.unit_id end unit_id,
        p.pad_seq pay_dist_seq_nbr,
        ph.payroll_header_id payroll_header_id,
        p.pad_id vista_paydist_id,
        p.pad_beg_payperiod pay_prd_beg_dt,
        p.pad_end_payperiod pay_prd_end_d
     from
        stg_paydist p
        inner join company c on c.vista_company_id = p.emp_ni
        inner join payroll_header ph on ph.vista_payroll_id = p.pay_id
        left outer join unit u on u.vista_unit_id = p.uni_ni
     where ph.deleted = '0'
  ) ps
     on (ps.vista_paydist_id = ep.vista_paydist_id)

  when matched then
  update
     set ep.vista_payroll_id      = ps.vista_payroll_id,
         ep.pay_dte               = ps.pay_dte,
         ep.client_id             = ps.client_id,
         ep.company_id            = ps.company_id,
         ep.unit_id               = ps.unit_id,
         ep.pay_dist_seq_nbr      = ps.pay_dist_seq_nbr,
         ep.payroll_header_id     = ps.payroll_header_id

  when not matched then
  insert (
     ep.employee_payment_id,
     ep.vista_payroll_id,
     ep.pay_dte,
     ep.client_id,
     ep.company_id,
     ep.unit_id,
     ep.pay_dist_seq_nbr,
     ep.payroll_header_id,
     ep.vista_paydist_id
  ) values (
     seq_employee_payments.nextval,
     ps.vista_payroll_id,
     ps.pay_dte,
     ps.client_id,
     ps.company_id,
     ps.unit_id,
     ps.pay_dist_seq_nbr,
     ps.payroll_header_id,
     ps.vista_paydist_id
  ) log errors into errorlog (v_batch || 'EMPLOYEE_PAYMENT') reject limit unlimited;

3 个答案:

答案 0 :(得分:1)

处理大量数据需要花费大量时间...... 以下是一些可能对您有帮助的事情(假设没有执行计划不好的问题):

  1. 在UPDATE部分中添加where子句,仅在值实际不同时更新记录。如果要反复合并相同的数据,并且实际只修改了较小的数据子集,则可以提高性能。

  2. 如果您确实一遍又一遍地处理相同的数据,请调查是否可以添加一些修改标记/日期以仅处理自上次以来的新记录。

  3. 根据环境的类型以及更新源表的时间/人员,调查truncate-insert方法是否有益。请记住事先将索引设置为不可用。

  4. 我认为您最好的选择是利用数据中的模式。这是oracle不知道的事情,所以你可能需要发挥创意。

答案 1 :(得分:1)

尝试使用Oracle提示:

MERGE /*+ append leading(PS) use_nl(PS EP) parallel (12) */

尝试使用提示来优化内部使用查询。

答案 2 :(得分:0)

我正在研究类似的问题,发现一个好的解决方案是将查询分解。 大表合并不是一个好主意的主要原因是由于使用查询结果在内存中的存储。由于PGA很快就被填满,因此数据库开始使用排序操作的临时表空间并进行连接。磁盘上的临时表空间非常慢。通过将查询分为两个查询,可以轻松避免使用过多的临时表空间。 因此,以下查询

merger into emp e
using ( 
select a,b,c,d from (/* big query here */)
) ec
on /*conditions*/
when matched then
/* rest of merge logic */

可以成为

create table temp_big_query as select a,b,c,d from (/* big query here */);
merger into emp e
using ( 
select a,b,c,d from temp_big_query
) ec
on /*conditions*/
when matched then
/* rest of merge logic */

如果using查询还具有CTE和子查询,请尝试分解该查询以使用更多临时表,例如上面显示的临时表。还应避免使用并行提示,因为它们通常会降低查询速度,除非查询本身具有可以并行完成的功能,而应尝试使用索引,而应尽可能多地使用并行作为优化的最后选择。 我知道缺少一些参考,请随时发表评论并添加参考或指出我的答案中的错误。

相关问题