Insert 语句会比 Oracle 中的 merge 语句执行得更好吗

Would Insert statement perform better than a merge statement in Oracle

请问如果我们不需要做任何更新,Insert 语句会比 Oracle 中的 merge 语句执行得更好吗?

据我所知,如果我们需要 运行 同时为相同的 table 插入和更新语句,则单个合并语句通常是首选选项。但是,如果我只有一个插入语句怎么办?

我有 20 个 table 这样的

Create Table Txn_History nologging (
ID number,
Comment varchar2(300),
... (Another 20 columns),
Std_hash raw(1000) 
);

Alter table Txn_History add constraint Order_line_PK Primary (Std_hash);

还有 20 个分期 table 像这样

Create Table Order_line_staging nologging (
ID number,
Comment varchar2(300),
... (Another 20 columns),
Std_hash raw(1000) 
);

Alter table Order_line_staging add constraint Order_line_PK Primary (Std_hash);

每个 Txn_History table 现在有 4000 万行,我将分批从每个相应的 Txn_History_staging 插入另外 5000 万行。每批有 100 万行。在每次迭代结束时,暂存 table 将使用清除语句删除。

以下是我的合并语句

Merge into Txn_History Target
using Txn_History_Staging source on
    (source.std_hash = Target.std_has)
when not matched then
   insert(
      ID,
      Comment,
      ... (Another 20 columns),
      std_hash
   ),
   values
   (
       Target.ID,
       Target.comment,
       ... (Another 20 columns),
       Target.std_hash
   );

我的数据库处于存档日志模式(FORCE_LOGGING = 'NO'),我注意到每次迭代需要 2 小时才能完成 运行,并且仍然生成 25GB 存档日志事件日志记录。

所以我怀疑合并语句生成了归档日志。

如果我改用下面的插入语句会不会更好:

insert /*+append */ into Txn_History Target
select
    *
from
   Txn_History_staging Source
where
    Source.std_hash not in (select distinct std_hash  from txn_history);

它会有更好的性能吗(即 运行 更快并且生成的日志更少)?

提前致谢!

可能 是您的 INSERT 会执行得更好,但真正的证据在于执行。如果您将 HASH ANTI JOIN 视为派生所需行的机制,那通常接近最佳。

存档生成是数据库中记录的更改的结果,因此标准 MERGE(最终执行插入)或 INSERT 将生成非常相似的存档量。

区分因素更有可能是 APPEND 提示。就其本身而言(在默认为 LOGGING 的 table 上),您可能会看到

  • no/tiny 如果 table 未编入索引
  • ,则归档日志减少
  • 如果table被索引
  • ,归档日志会减少一些

真正的收益来自于你在加载之前进行 table NOLOGGING,并在加载之前将索引设置为 UNUSABLE,这可以将归档日志生成减少到几乎 none,但是当然你需要明白这样做的后果

  • 您需要备份受影响的数据文件
  • 您可能需要对备用数据库采取一些修复措施
  • 你需要重建那些索引

像大多数事情一样,它基本上是一个 cost/benefit 分析