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 分析
请问如果我们不需要做任何更新,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 分析