以下是我的存储过程的小片段。我正在使用Oracle数据库。 我觉得下面不是好方法。首先,我正在检查天气我从查询中得到一行。然后,如果count(CNT2> 0)大于0意味着我从查询中获取记录,那么我再次执行查询以获取列。
这是一种重复的查询。首先,我正在检查计数,然后再次执行查询,如果count大于0.
我的程序中有10个查询,对于每个查询,我首先检查计数然后再次执行查询,如果count大于0.我认为这对于性能观点来说并不好。
我在网上查了一下,发现我们可以通过DATANOTFOUND异常捕获它,并且可以使用外部游标。我是新手,不知道该怎么做。哪一个是性能观点的更好选择。
.............
.............
BEGIN
oAuditMsg := 'audit : ';
DBMS_OUTPUT.PUT_LINE('Debug :: inside begin' );
select count(*) into CNT2 from COMMON_MAPPING where IP like VAR_IP ;
IF CNT2 >0 THEN
select Out_IP,Out_IP1 into VAR_OUTIP, VAR_OUTIP1 from from COMMON_MAPPING where IP like VAR_IP ;
ELSE
DBMS_OUTPUT.PUT_LINE('No Record found in table COMMON_MAPPING');
END IF;
..............
..............
..............
答案 0 :(得分:1)
我在网上查了一下,发现我们可以通过DATANOTFOUND异常
来捕获它
您需要使用 NO_DATA_FOUND 例外。
例如,
SQL> SET serveroutput ON
SQL> DECLARE
2 v_ename VARCHAR2(20);
3 v_empno NUMBER;
4 BEGIN
5 v_empno := 9999;
6 SELECT ename INTO v_ename FROM emp WHERE empno = v_empno;
7 IF v_ename IS NOT NULL THEN
8 dbms_output.put_line('Employee found');
9 -- do something
10 END IF;
11 EXCEPTION
12 WHEN no_data_found THEN
13 dbms_output.put_line('Inside Exception because Employee not found');
14 -- do something
15 WHEN OTHERS THEN
16 DBMS_OUTPUT.PUT_LINE ('Unexpected error');
17 RAISE;
18 END;
19 /
Inside Exception because Employee not found
PL/SQL procedure successfully completed.
通常,您不在生产代码中使用 DBMS_OUTPUT ,使用异常块将错误记录到错误记录表中。它应该是健壮的,有助于开发人员轻松地理解错误以进行调试。
异常处理程序的优点
使用异常处理程序进行错误处理使程序更容易 写作和理解,并减少未处理的可能性 异常。
没有异常处理程序,您必须检查每个可能的错误, 它可能发生的任何地方,然后处理它。这很容易 忽略可能的错误或可能发生的地方,尤其是 如果错误不能立即检测到(例如,错误的数据 在计算中使用它之前可能无法检测到)。 错误处理代码分散在整个程序中。
使用异常处理程序,您无需知道每个可能的错误或 它可能发生在任何地方。你只需要包括一个 每个块中可能发生错误的异常处理部分。在里面 异常处理部分,您可以包含两者的异常处理程序 具体和未知错误。如果块中的任何位置发生错误 (包括在子块内),然后异常处理程序处理它。 错误处理代码在异常处理部分中被隔离 块。
关于您的效果问题:
并且可以使用外部光标。
我认为你的意思是显式光标。从性能的角度来看,这不是一个好主意。我希望结合使用 CURSOR FOR LOOP 和 FOR ALL 语句以及 BULK COLLECT 。
在最近的Oracle版本中,通过内部bulk collect limit 100
更好地优化 CURSOR FOR LOOP 。
但是,它不只是关于批量收集,我们正在处理我们随后将对我们已逐步获取的数组执行的操作。我们可以通过使用FORALL语句和BULK COLLECT进一步提高性能。
话虽如此,如果你能在纯SQL 中做到这一点会快得多。 SQL和PL / SQL不同,当您在PL / SQL 中执行 SQL调用时,需要在两个引擎之间进行上下文切换,反之亦然,即 PL / SQL调用SQL 即可。随着两个引擎之间的每个上下文切换,都存在性能开销。当SQL调用PLSQL时,“命中”最明显 - 当SQL嵌入PLSQL时,其他方式则不然。
答案 1 :(得分:0)
你有3种可能性。
您的计数方法不安全(我的选项2)。 如果另一个会话在带有count的行之后和带有select ...的行之前删除满足条件的行 - 代码将抛出一个未处理的异常......
选项1是首选。但是,由于处理异常,性能可能会略低一些。但是,与没有处理异常的问题相比,它并不重要。 您提到了选项3 - 有一个示例如何使用它。
选项1:
select Out_IP,Out_IP1 INTO VAR_OUTIP, VAR_OUTIP1 from COMMON_MAPPING where IP like VAR_IP;
EXCEPTION
WHEN NO_DATA_FOUND
...
选项2:
select count(*) into CNT2 from COMMON_MAPPING where IP like VAR_IP ;
IF CNT2 >0 THEN
select Out_IP,Out_IP1 into VAR_OUTIP, VAR_OUTIP1 from from COMMON_MAPPING where IP like VAR_IP ;
选项3:
DECLARE
BEGIN
FOR foo_rec IN ( select Out_IP,Out_IP1 from COMMON_MAPPING where IP like VAR_IP)
LOOP
...
END LOOP;
EXCEPTION
WHEN OTHERS THEN
RAISE;
END ;
答案 2 :(得分:0)
根据提供的问题陈述。我可以建议以下两种方法。 第一个选项是使用Ref Cursor,因为您不必担心这种异常处理。 - 我的最爱 第二种方法如上所述,在异常块中捕获异常。我在异常处理中包含了另一个OTHERS子句,因为可能会发生其他错误,例如TOO_MANY_ROWS。
-- Option 1 --> Using Ref Cursor
DECLARE
CNT2 PLS_INTEGER:=0;
oAuditMsg VARCHAR2(100 CHAR);
VAR_OUTIP VARCHAR2(100 CHAR);-- Assuming this field is VARCHAR
VAR_OUTIP1 VARCHAR2(100 CHAR);-- Assuming this field is VARCHAR
VAR_IP VARCHAR2(100 CHAR);
p_lst sys_refcursor;
BEGIN
oAuditMsg:= 'audit : ';
DBMS_OUTPUT.PUT_LINE('Debug :: inside begin' );
OPEN p_lst FOR SELECT Out_IP, Out_IP1 FROM COMMON_MAPPING WHERE IP LIKE VAR_IP ;
END;
-- Option 2 --> Using NoDataFound Exception Clause
DECLARE
-- CNT2 PLS_INTEGER:=0; -- Not required
oAuditMsg VARCHAR2(100 CHAR);
VAR_OUTIP VARCHAR2(100 CHAR);-- Assuming this field is VARCHAR
VAR_OUTIP1 VARCHAR2(100 CHAR);-- Assuming this field is VARCHAR
VAR_IP VARCHAR2(100 CHAR);
-- p_lst sys_refcursor; -- Not required
BEGIN
oAuditMsg:= 'audit : ';
DBMS_OUTPUT.PUT_LINE('Debug :: inside begin' );
BEGIN
SELECT Out_IP, Out_IP1
INTO
VAR_OUTIP,
VAR_OUTIP1
FROM COMMON_MAPPING WHERE IP LIKE VAR_IP ;
EXCEPTION WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20001,SQLERRM,TRUE);
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,SQLERRM,TRUE);
END;
END;
如果有帮助,请告诉我。