我创建了一个Oracle块来检查在关联数组上使用nocopy的效果;创建一个包含1000000个元素的数组,并将其作为参数传递给两个相同的方法,第一次作为输出参数,第二次作为输出nocopy。代码如下所示:
declare
type my_type is table of varchar2(32767) index by binary_integer;
my_array my_type;
st number;
rt number;
procedure in_out(m1 in out my_type)
is
begin
dbms_output.put_line(my_array(1));
end in_out;
procedure in_out_nocopy(m1 in out nocopy my_type)
is
begin
dbms_output.put_line(my_array(1));
end in_out_nocopy;
begin
for i in 1..999999 loop
my_array(i) := '123456789012345678901234567890123456789012345678901234567890abcd';
end loop;
st := dbms_utility.get_time;
in_out(my_array);
rt := (dbms_utility.get_time - st)/100;
dbms_output.put_line('Time needed for in out is: ' || rt || ' 100''ths of second!');
st := dbms_utility.get_time;
in_out_nocopy(my_array);
rt := (dbms_utility.get_time - st)/100;
dbms_output.put_line('Time needed for in out nocopy is: ' || rt || ' 100''ths of second!');
end;
现在,这将报告nocopy方法在.27秒后表现更好。我对两件事情感到困惑:
i)如果我将两种方法的主体改为
begin
null;
end;
没有时间差异,但参数传递的差异仍然存在。为什么会这样?
ii)如果我将程序机构保留为
begin
null;
end;
这一次,而不是将参数定义为out in in out nocopy,我将其定义为out out out nocopy我确实得到了时间差。我认为参数是重新初始化的,所以为什么我在这里得到时间差而不是在外面的情况?
此致 的Christos
答案 0 :(得分:7)
不错的测试用例,我在Oracle 11gR1(11.1.0.7.0)中获得了相同的结果。
以下是文档在NOCOPY
上所说的内容:
NOCOPY提示(在“NOCOPY”中描述)。
默认情况下,PL / SQL按值传递OUT和IN OUT子程序参数。在运行子程序之前,PL / SQL将每个OUT和IN OUT参数复制到临时变量,该变量在子程序执行期间保存参数的值。如果子程序正常退出,则PL / SQL将临时变量的值复制到相应的实际参数。如果子程序退出时出现未处理的异常,则PL / SQL不会更改实际参数的值。
当OUT或IN OUT参数表示大型数据结构(如集合,记录和ADT实例)时,复制它们会降低执行速度并增加内存使用量 - 尤其是对于ADT实例。
对于每次调用ADT方法,PL / SQL都会复制ADT的每个属性。如果方法正常退出,则PL / SQL将应用该方法对属性所做的任何更改。如果退出方法时出现未处理的异常,则PL / SQL不会更改属性。
如果子程序以未处理的异常结束,程序不要求OUT或IN OUT参数保留其预调用值,则在参数声明中包含NOCOPY提示。 NOCOPY提示请求(但不保证)编译器通过引用而不是值传递相应的实际参数。
请注意,NOCOPY
仅被描述为提示(即不是命令)。有时会not be respected。
无论如何,NOCOPY的行为是case(1)和(3)的标准(是的,PL / SQL将在出错时恢复OUT参数的值)。 (2)怎么样?
我认为在(2)情况下NULL过程是optimized。让我们尝试关闭优化:
SQL> alter session set plsql_optimize_level=0;
Session altered
SQL> DECLARE
2 TYPE my_type IS TABLE OF LONG INDEX BY BINARY_INTEGER;
3 my_array my_type;
4 st NUMBER;
5 rt NUMBER;
6 PROCEDURE in_out(m1 IN OUT my_type) IS
7 BEGIN
8 NULL;--dbms_output.put_line(my_array(1));
9 END in_out;
10 PROCEDURE in_out_nocopy(m1 IN OUT NOCOPY my_type) IS
11 BEGIN
12 NULL;--dbms_output.put_line(my_array(1));
13 END in_out_nocopy;
14 BEGIN
15 FOR i IN 1 .. 9999999 LOOP
16 my_array(i) :=
17 '123456789012345678901234567890123456789012345678901234567890abcd';
18 END LOOP;
19 st := dbms_utility.get_time;
20 in_out(my_array);
21 rt := (dbms_utility.get_time - st) / 100;
22 dbms_output.put_line('Time needed for in out is: '
23 || rt || ' seconds!');
24 st := dbms_utility.get_time;
25 in_out_nocopy(my_array);
26 rt := (dbms_utility.get_time - st) / 100;
27 dbms_output.put_line('Time needed for in out nocopy is: '
28 || rt || ' seconds!');
29 END;
30 /
Time needed for in out is: 5,59 seconds!
Time needed for in out nocopy is: 0 seconds!
正如所料,差异神奇地再次出现:)