对于nocopy参数,了解的时间也不是很长。一般我们在写函数或过程的时候,使用out的情况比较少,更不提效率上觉察到差别了。
后来了解到指定nocopy时,效率要比不指定的要高。但是不知道为什么。
今天看到了一篇Oracle优化文档,看出了一些端倪。
当遇到异常时,plsql在这层之上增加了一些处理,以确保过程或函数的行为是正确的。如:
当外部指定的out参数已经有一个值,在调用函数时出现了异常,此时plsql将返回该参数原来的值,而不是在函数处理过程中的某个值。
以上是没有指定nocopy的情况,当指定了该参数时,plsql将不会增加这些处理,因此外部指定的out参数将是函数执行过程中的某个值。
实验:
(20111026更新)
有nocopy的情况:
SQL> declare
2 v_num number := 0;
3 procedure gets(p_val outnocopynumber)as
4 begin
5 p_val := 3.1415;
6 raise_application_error(-20001, 'aa');
7 end gets;
8 begin
9 begin
10 gets(v_num);
11 exception when others then
12 dbms_output.put_line(v_num);
13 end;
14 end;
15 /
3.1415
PL/SQL procedure successfully completed
无nocopy的情况:
SQL> declare
2 v_num number := 0;
3 procedure gets(p_val out/*nocopy */number)as
4 begin
5 p_val := 3.1415;
6 raise_application_error(-20001, 'aa');
7 end gets;
8 begin
9 begin
10 gets(v_num);
11 exception when others then
12 dbms_output.put_line(v_num);
13 end;
14 end;
15 /
0
PL/SQL procedure successfully completed
红色部分是两者的差异,其他都一样,其结果就是nocopy的作用。通常在对象、集合、记录类型的参数传递时会有明显效果(效果显著视copy的数据量而定)。
################################
增加一个过程:prc(ret in out varchar2);
create or replace procedure prc(
ret in out pls_integer) as
begin
ret := 2;
raise_application_error(-20001, 'out test!');
end prc;
用以下匿名过程进行测试:
declare
vv pls_integer := 1;
excep exception;
pragma exception_init(excep, -20001);
begin
prc(vv);
exception when excep then
dbms_output.put_line(vv);
end;
观察当ret in out 指定了nocopy参数和没指定时的输出值:
SQL> set serveroutput on
SQL>
SQL> create or replace procedure prc(
2 ret in out pls_integer) as
3 begin
4 ret := 2;
5 raise_application_error(-20001, 'out test!');
6 end prc;
7 /
Procedure created
SQL>
SQL> declare
2 vv pls_integer := 1;
3 excep exception;
4 pragma exception_init(excep, -20001);
5 begin
6 prc(vv);
7 exception when excep then
8 dbms_output.put_line(vv);
9 end;
10 /
1
PL/SQL procedure successfully completed
发现此时的输出值是1,即保留了原来的值。
使用nocopy参数:
SQL>
SQL> create or replace procedure prc(
2 ret in out nocopy pls_integer) as
3 begin
4 ret := 2;
5 raise_application_error(-20001, 'out test!');
6 end prc;
7 /
Procedure created
SQL>
SQL> declare
2 vv pls_integer := 1;
3 excep exception;
4 pragma exception_init(excep, -20001);
5 begin
6 prc(vv);
7 exception when excep then
8 dbms_output.put_line(vv);
9 end;
10 /
2
PL/SQL procedure successfully completed
此时变为2,即过程中的那个值。nocopy使plsql在执行过程中不再对out参数值做特殊的管理,使得总体的性能得到了提高。