当前位置:  开发笔记 > 编程语言 > 正文

Oracle PL/SQL - NO_DATA_FOUND异常对存储过程性能有害吗?

如何解决《OraclePL/SQL-NO_DATA_FOUND异常对存储过程性能有害吗?》经验,为你挑选了3个好方法。

我正在编写一个存储过程,需要在其中进行大量调整.根据C#.NET编码的一般知识,异常会损害性能,我总是避免在PL/SQL中使用它们.我在这个存储过程中的条件主要围绕是否存在记录,我可以用两种方法之一:

SELECT COUNT(*) INTO var WHERE condition;
IF var > 0 THEN
   SELECT NEEDED_FIELD INTO otherVar WHERE condition;
....

-要么-

SELECT NEEDED_FIELD INTO var WHERE condition;
EXCEPTION
WHEN NO_DATA_FOUND
....

第二种情况对我来说似乎更优雅,因为那时我可以使用NEEDED_FIELD,我必须在第一种情况下的条件之后的第一个语句中选择.更少的代码.但是如果存储过程使用COUNT(*)运行得更快,那么我不介意再输入一点来弥补处理速度.

任何提示?我错过了另一种可能吗?

编辑 我应该提到这已经嵌套在FOR LOOP中了.不确定这是否与使用游标有所不同,因为我认为我不能将光标作为FOR LOOP中的选择进行DECLARE.



1> RussellH..:

我不会使用显式游标来执行此操作.当可以使用隐式游标时,Steve F.不再建议人们使用显式游标.

该方法count(*)不安全.如果另一个会话删除符合条件的行后面的行count(*),并且在行之前select ... into,代码将抛出一个无法处理的异常.

原始帖子的第二个版本没有这个问题,通常是首选.

也就是说,使用异常会有一个小的开销,如果你100%确定数据不会改变,你可以使用count(*),但我建议不要这样做.

我在32位Windows上运行Oracle 10.2.0.1上的这些基准测试.我只关注经过的时间.还有其他测试工具可以提供更多细节(例如锁存器计数和使用的内存).

SQL>create table t (NEEDED_FIELD number, COND number);

表创建.

SQL>insert into t (NEEDED_FIELD, cond) values (1, 0);

已创建1行.

declare
  otherVar  number;
  cnt number;
begin
  for i in 1 .. 50000 loop
     select count(*) into cnt from t where cond = 1;

     if (cnt = 1) then
       select NEEDED_FIELD INTO otherVar from t where cond = 1;
     else
       otherVar := 0;
     end if;
   end loop;
end;
/

PL/SQL过程成功完成.

经过时间:00:00:02.70

declare
  otherVar  number;
begin
  for i in 1 .. 50000 loop
     begin
       select NEEDED_FIELD INTO otherVar from t where cond = 1;
     exception
       when no_data_found then
         otherVar := 0;
     end;
   end loop;
end;
/

PL/SQL过程成功完成.

经过时间:00:00:03.06



2> Noah Yetter..:

由于SELECT INTO假定将返回单个行,因此您可以使用以下形式的语句:

SELECT MAX(column)
  INTO var
  FROM table
 WHERE conditions;

IF var IS NOT NULL
THEN ...

SELECT将为您提供值(如果有),值为NULL而不是NO_DATA_FOUND异常.由于结果集包含单行,MAX()引入的开销将为最小为零.它还具有相对于基于游标的解决方案而言紧凑的优点,并且不易受原始帖子中的两步解决方案等并发问题的影响.


此解决方案的缺点是它会隐藏您可能不想隐藏的其他异常情况,因为它不应该发生,例如TOO_MANY_ROWS异常.

3> DCookie..:

@ Steve的代码的替代品.

DECLARE
  CURSOR foo_cur IS 
    SELECT NEEDED_FIELD WHERE condition ;
BEGIN
  FOR foo_rec IN foo_cur LOOP
     ...
  END LOOP;
EXCEPTION
  WHEN OTHERS THEN
    RAISE;
END ;

如果没有数据,则不执行循环.光标FOR循环是要走的路 - 它们有助于避免大量的内务管理.更紧凑的解决方案:

DECLARE
BEGIN
  FOR foo_rec IN (SELECT NEEDED_FIELD WHERE condition) LOOP
     ...
  END LOOP;
EXCEPTION
  WHEN OTHERS THEN
    RAISE;
END ;

如果您在编译时知道完整的select语句,那么哪个有用.

推荐阅读
落单鸟人
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有