0

请问如果我们不需要进行任何更新,插入语句会比 Oracle 中的合并语句执行得更好吗?

我知道,如果我们需要同时为同一个表运行插入和更新语句,则单个合并语句通常是首选选项。但是如果我只有一个插入语句呢?

我有20张这样的桌子

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个这样的临时表

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 表现在有 4000 万行,我将分批从每个对应的 Txn_History_staging 中插入另外 5000 万行。每批有 100 万行。在每次迭代结束时,将使用 purge 语句删除临时表。

以下是我的合并声明

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 归档日志事件 nologging is on。

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

如果我使用以下插入语句会更好:

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);

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

提前致谢!

4

1 回答 1

3

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

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

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

  • 如果表没有被索引,归档日志中没有/微小的减少
  • 如果表被索引,归档日志会有所减少

真正的收获是您在加载之前将表设置为 NOLOGGING,并在加载之前将索引设置为 UNUSABLE,这可以将归档日志生成压缩到几乎没有,但当然您需要了解这样做的后果

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

像大多数事情一样,它基本上是成本/收益分析

于 2021-07-13T01:36:53.327 回答