plsql下nocopy参数的含义

本文深入探讨了在PL/SQL中使用nocopy参数如何优化out参数的传递效率,通过实验展示了在异常处理场景下,指定nocopy参数避免了额外的处理步骤,从而提升了整体性能。主要关注于参数传递机制与性能优化。

对于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参数值做特殊的管理,使得总体的性能得到了提高。

 

 

转自http://space.itpub.net/12932950/viewspace-629399


<think>嗯,用户想了解如何在PL/SQL中调用带有入参和出参的存储过程。首先,我需要回忆一下PL/SQL的基本结构,特别是存储过程的调用方法。 首先,用户可能已经知道存储过程的基本概念,但需要具体的调用示例。需要分步骤说明,从创建存储过程开始,然后是如何调用它。入参和出参的处理是关键点,需要详细说明参数传递的方式。 接下来,应该考虑不同的调用场景,比如在匿名块中调用,或者在另一个存储过程中调用。用户可能想知道如何声明变量来接收出参,以及如何绑定参数。此外,参数模式(IN、OUT、IN OUT)的区别也需要解释清楚,避免混淆。 可能还需要提醒常见的错误,比如参数顺序不匹配,或者没有正确声明变量来接收输出参数。另外,使用工具如SQL Developer或SQL*Plus时的注意事项,比如在SQL*Plus中使用VARIABLE绑定变量,这也是用户可能会遇到的问题。 还要考虑用户的实际应用场景,比如他们是否在调试或者在生产环境中使用,是否需要事务控制,比如COMMIT的位置。示例中的具体操作,比如更新员工工资,是否合理,是否需要更通用的例子。 最后,确保回答结构清晰,步骤明确,语法正确,符合用户的要求。可能需要检查示例中的代码是否正确,比如存储过程的创建语句是否有语法错误,调用部分是否缺少分号等。同时使用中文,避免专业术语的直译,让内容更易懂。</think>PL/SQL调用存储过程的步骤如下(含入参和出参): 一、创建存储过程示例 ```sql CREATE OR REPLACE PROCEDURE update_salary( p_emp_id IN NUMBER, -- 输入参数 p_percent IN NUMBER, -- 输入参数 p_new_salary OUT NUMBER -- 输出参数 ) IS BEGIN UPDATE employees SET salary = salary * (1 + p_percent/100) WHERE employee_id = p_emp_id RETURNING salary INTO p_new_salary; -- 将结果返回到输出参数 COMMIT; EXCEPTION WHEN NO_DATA_FOUND THEN p_new_salary := -1; -- 错误标识 END update_salary; ``` 二、调用存储过程方法 1. 匿名块调用(最常用) ```sql DECLARE v_result_salary NUMBER; BEGIN update_salary( p_emp_id => 100, -- 传入员工ID p_percent => 10, -- 涨薪10% p_new_salary => v_result_salary -- 接收返回的新工资 ); DBMS_OUTPUT.PUT_LINE('新工资:' || v_result_salary); END; ``` 2. 在另一个存储过程中调用 ```sql CREATE OR REPLACE PROCEDURE salary_management IS v_final_salary NUMBER; BEGIN update_salary(101, 15, v_final_salary); -- 可继续处理v_final_salary... END; ``` 三、关键注意事项 1. 参数模式: - `IN`:只输入(默认模式) - `OUT`:只输出(必须在调用前声明变量) - `IN OUT`:双向参数 2. SQL*Plus中调用需绑定变量: ```sql VARIABLE g_salary NUMBER; EXEC update_salary(200, 5, :g_salary); PRINT g_salary; ``` 3. 异常处理建议: ```sql BEGIN update_salary(...); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('错误代码:' || SQLCODE); DBMS_OUTPUT.PUT_LINE('错误信息:' || SQLERRM); END; ``` 四、调试技巧 1. 使用`DBMS_OUTPUT`显示中间值 2. 在存储过程内部添加异常日志记录 3. 用`%TYPE`声明变量保证类型一致: ```sql DECLARE v_result employees.salary%TYPE; ``` 实际开发中,建议: 1. 给参数添加前缀(如p_表示参数) 2. 对OUT参数做有效性验证 3. 重要操作添加事务控制(如COMMIT/ROLLBACK) 4. 使用`NOCOPY`提示优化大型参数传递(适用于Oracle
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值