【问题标题】:is sql faster than plsql in oracleoracle中sql比plsql快吗
【发布时间】:2020-01-13 08:54:48
【问题描述】:

使用批量收集或正常合并更新?

我正在尝试使用批量收集和正常合并来检查更新的性能。 我发现当我们在匿名块中使用简单合并时性能会更好。 当我使用批量收集时,需要更多时间。

如果普通更新(合并)比批量收集快,那么为什么 oracle 引入了它?我们实际上在哪里看到了批量收集的好处?

declare 
l_start integer;
l_end integer;
begin
l_start := dbms_utility.get_time;
merge into test111 t1
using test112 t2
on (t1.col1 = t2.col3)
when matched then update 
set t1.col2 = t1.col2*5;
l_end := dbms_utility.get_time;
dbms_output.put_line(l_end - l_start);
end;
declare
type nt_test is table of test112.col3%TYPE;
nt_val nt_test := nt_test();
cursor c is select col3 from test112;
c_limit integer := 100;
l_start integer;
l_end integer;
begin
l_start := DBMS_UTILITY.get_time;
open c;
loop

fetch c 
bulk collect into nt_val limit c_limit;
exit when nt_val.count = 0;

forall i in indices of nt_val
update test111 set col2 = col2/ 5
where col1 = nt_val(i);
commit;

end loop;
l_end := dbms_utility.get_time;
dbms_output.put_line(l_end - l_start);
end;

我在合并查询中获得 0.797 秒,在批量收集中获得 171.352 秒

【问题讨论】:

  • 关注多少行?为什么以100 为限制?循环提交通常是性能杀手。
  • SQL 到 PL/SQL 引擎是一个消耗更多时间和资源的上下文切换。只需运行 MERGE 语句而不使用任何匿名块。如果需要执行时间,则在sqlplus中运行,设置time on timing on。
  • 如果我给你一个勺子、一个桶和一个装满水的浴缸,然后让你尽快倒空,你会用什么?您可能会说水桶,但实际上拔插头更快!用数据库术语来说,spoon 代表逐行处理(例如一个 cursor for loop),bucket 代表批量收集处理,拔掉插头就是 SQL 解决方案。
  • 如果普通更新(合并)比批量收集快,那Oracle为什么要引入呢?因为它们不一样。您可能出于其他原因想要填充数组。数组可能会作为参数传递到您的过程中,等等。

标签: sql plsql oracle11g bulkinsert query-performance


【解决方案1】:

如果您可以在 SQL 中执行此操作,那么在 SQL 中执行几乎总是更有效。如果您必须求助于 PL/SQL,因为您正在执行一些受益于过程代码的处理,那么执行 bulk collectforall 将比旧样式的逐行处理更有效(尽管如果您'正在使用隐式游标,最新版本的 Oracle 将在幕后自动执行 bulk collect,因此差异没有以前那么大)。

在您的测试中,我希望循环中的提交能够解释运行时的大部分差异。显然,这在功能上与 SQL 解决方案不同。

【讨论】:

  • 总的来说,同意贾斯汀的观点。然而,想要更全面地解释这个评论:“(尽管如果您使用隐式游标,最新版本的 Oracle 将在幕后自动进行批量收集,因此差异没有以前那么大)。 " (1) 如果您正在执行游标 FOR 循环并在其中执行逐行 DML(插入、更新、删除),Oracle 将自动优化 CFL 以在每次提取时返回 100 行。这类似于 FETCH-BULK COLLECT-LIMIT 100。但它实际上并未重新编码为 BULK COLLECT 语句。那时它是C代码。 :-)
  • (不习惯处理 cmets 上的 SO 限制)(2) 这对逐行 DML 执行没有帮助,这将是您真正感到痛苦的地方。因此,该建议主要适用于不包含任何非查询 DML 的“只读”游标 FOR 循环。
  • 谢谢@Justin Cave!感谢您对此主题的澄清。我再次测试它,我现在看到了时间增益:)
  • 谢谢@Steven Feuerstein!为了澄清
【解决方案2】:

如果您可以在 SQL 中执行此操作,它总是会更快,但即便如此 171.352 也是非常高的价值。所以我做了我的测试,我在 test111(col1) 上添加了一个索引,并且使用相同的 pl/sql 块,它在 0.20 秒内完成。

【讨论】:

  • 只是一个历史记录。 “如果正常更新(合并)比批量收集更快,那么为什么 oracle 引入了它?”问题中暗示的断言。不正确,因为版本 9i 中引入了合并,而之前在 8(或 8i)中引入了批量收集。
猜你喜欢
  • 2018-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-26
  • 1970-01-01
  • 2010-12-25
相关资源
最近更新 更多