如何提高 FORALL 插入例程的性能?

Posted

技术标签:

【中文标题】如何提高 FORALL 插入例程的性能?【英文标题】:How to improve performance of FORALL insert routine? 【发布时间】:2018-08-31 11:54:33 【问题描述】:

我需要在 Oracle 中通过批量收集插入所有不存在于表中的记录。我的代码在这里,太费时间了。

forall i in 1 .. arr_upd_mbr.count save exceptions
      insert into claim.member_contact(member_id_rx, addr_street, addr_apt, 
        addr_city, addr_state, addr_zip, contact_phone,
        start_dt, end_dt, gender, dob)
      select 
        arr_upd_mbr(i).member_id_rx, arr_upd_mbr(i).mbr_addr_street, arr_upd_mbr(i).mbr_addr_apt,
        arr_upd_mbr(i).mbr_addr_city, arr_upd_mbr(i).mbr_addr_state, arr_upd_mbr(i).mbr_addr_zip || arr_upd_mbr(i).zip_reserve,
        arr_upd_mbr(i).primary_phone, trunc(sysdate), arr_upd_mbr(i).elg_end_dt,
        arr_upd_mbr(i).mbr_gender, arr_upd_mbr(i).mbr_dob
      from dual
      where not exists(select 1
                       from claim.member_contact
                       where member_id_rx            = arr_upd_mbr(i).member_id_rx
                         and nvl(addr_street, '~')   = nvl(arr_upd_mbr(i).mbr_addr_street, '~')
                         and nvl(addr_apt, '~')      = nvl(arr_upd_mbr(i).mbr_addr_apt, '~')
                         and nvl(addr_city, '~')     = nvl(arr_upd_mbr(i).mbr_addr_city, '~')
                         and nvl(addr_state, '~')    = nvl(arr_upd_mbr(i).mbr_addr_state, '~')
                         and nvl(addr_zip, '~')      = nvl((arr_upd_mbr(i).mbr_addr_zip || arr_upd_mbr(i).zip_reserve), '~')
                         and nvl(contact_phone, '~') = nvl(arr_upd_mbr(i).primary_phone, '~')
                         and nvl(gender, '~')        = nvl(arr_upd_mbr(i).mbr_gender, '~')
                         and nvl(dob, v_last_date)   = nvl(arr_upd_mbr(i).mbr_dob, v_last_date)
                         and sysdate between start_dt and end_dt);
    exception
      when e_dml_errors then
        save_mem_change_exp(p_mbr_enrl_log_id_rx, 'MEMBER_CONTACT(Update)', arr_upd_mbr);
  end;

【问题讨论】:

【参考方案1】:

在 FORALL 中执行 not exists 将严重降低批量操作带来的任何性能优势。

您没有提供任何上下文,因此我们很难提供任何有意义的建议,但您可能会通过重写代码获得更好的性能。例如:

    重新访问子查询的 WHERE 子句。您所拥有的必须运行claim.member_contact 的全表扫描。也许您可以找到一种更好的方法来识别现有地址。 在填充数组时验证现有记录的存在,并丢弃不需要的记录。那么您的 FORALL 语句将只插入新记录。 忘记 FORALL ... INSERT 并改用 MERGE;您只需要编写 WHEN NOT MATCHED THEN INSERT 分支。

【讨论】:

非常感谢您的回复。让我试试合并

以上是关于如何提高 FORALL 插入例程的性能?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 APEX 应用程序的 csv 文件的批量数据插入中使用 forall 语句

SQL表值参数批量插入

使用 FORALL 和 RETURNING 插入表时如何获取 ROWID

Oracle PL/SQL 如何输出在 FORALL 语句中进行了多少次插入

Oracle pl/sql forall:如何计算表空间已满(1654)错误的实际插入行数

FORALL 插入目标表,然后从源表中删除 FORALL