PL/SQL 中如何正确选择游标类型

PL/SQL 中如何正确选择游标类型

PL/SQL里的游标可以分为显式和隐式两种,而隐式有分为select into隐式游标和for .. in 隐式游标两种。所以,我们可以认为,有3种游标用法: !E3o.Sc1`3_7du}
5|z ]P?Cn'S+ed
A. 显式游标 GgHJFM
@Cw~N S b
B. select into隐式游标
2kL Wq+J:vc
'||v~Tq/ C. for .. in 隐式游标
7z0xs.[[
.l-jawo+ti:Q 如何正确的选择使用哪种游标,将对你的程序的性能,可读性,代码量等产生重大影响…… 3K5M b8Dp
1@ Oi�M2b @#V/
--By RollingPig, XxbKIO+H/dx

P}fPAXza 本文简单的列举了PL/SQL中用到的几种不同类型的游标写法,并简单对比了不同游标写法的优缺点,同时给出了一个选择的基本原则。
L"c,L%D7/jRC j6y$q3q GpW$y ~J
本文并不包括太多的实际运行/性能测试,有兴趣的话,大家可以根据示例自己测试。 g"|)x6E8M{-bF;H

)AVMEv2a(P+~ 1.三种游标形式的简单例子
-~o8u(Y@�O(yH#q$i.@
P BT.r /t0p A. 显式游标
#[fu*D#nd1@ Qe
K(}~d*S 普通显式游标,指的是通过定义获得游标,并通过open,fetch,close的等方法来操作游标
aJmoHL u
h1|:Mb(|l#j G3h 代码:
&m#z7Ja8X�{X
&bF+~n-`+j1h!K m.V ]di+M].O3/
declare ;Jo3wJ I2dX
cursor c is select tname from tab ; A6MwD7fcG
l_tname varchar2(64);
2t/E/z&q'JjD9J8U�s begin +t#?'a,K7C
open c ; -CF6aI"Zp
loop
_"/1j.T|`�hO     fetch c into l_tname ; E#clV7UO/R{V
    exit when c%notfound ; zn2]7TK#L
    dbms_output.put_line(l_tname); S)[[QV0w(`:K
end loop; ,neUAgK'o-?
close c;
w"R)}}o+fP_f end; l)JM�T(h(K/~ /7j2y
/
aT9U3}OG} ..
W zFhx[xS .. `O4q'qX6z�d3fI
:C0quz E2omSn7K

:_D IW)@+f)N(kY&t Bulk Collect的 显式游标
3d7S6OcQ9/(W ;_Z9U X|
代码:
Un s;^.a
!@]h ST3D]X�n,G
j;E2W-T_A1N#Q#Y declare
U:G3kAzT cursor c is select tname from tab ; "_7Y a!v*k4RF
l_tname_array dbms_sql.varchar2_table;
:KS)y1@ O&t begin
i:v&q+t)j open c ; k Lg?*]&C^-t_ T
fetch c bulk collect into l_tname_array ;
l/Lm m|)N e6g for i in 1 .. l_tname_array.count loop
&C&|1jU&Z+J._0CfT     dbms_output.put_line(l_tname_array(i) );
g&H&_-/3feXkx8t*N end loop;
dSrK-i4iH[ close c; sJJ,F1wc:N*Y
end;
FQ aIve,rX / 8o4/}m?/tSY4P#|_;s
.. `QH^x
..

2006-9-27 12:43 小熊
Bulk Collect的 显式游标 + limit
^ |Lxp+y%T]f 8J"m3m/9^!~+_NW
代码: 3Hqf0c1V,_o

3fOm,Q$f/fnf
5`ms#x_ kSK declare
@'A*kI.B^y:h cursor c is select tname from tab ; N~Q-` _7C
l_tname_array dbms_sql.varchar2_table;
u7h3V_x5{V begin
P d],J?w open c ; /Lv3m7nzc D
loop nt]'Z'R
fetch c bulk collect into  l_tname_array limit 10 ; :lg9|r3Q%k:s+g5_
exit when c%notfound ; +oA9d2n}*Bf,V)^
        for i in 1 .. l_tname_array.count loop
/1P WD t2e(/tK                 dbms_output.put_line(l_tname_array(i) );
9Xq%X5Og.bh7Q         end loop;
CX&` `*SQWd end loop;
"pR V-T8j)B.t#j-B close c; Ya(pl?b
end; /qN8z2v*i2|_�y
/
eNh ujm-F .. u-[ G]#CH F
..
K2B,ltz*h
f'fWI9]/EgWJ 隐式游标相对于显式游标而言,指的是不需要事先Declare,也无须用open,fetch,close的等方法来操作,而是通过其它的方式来操作游标 Y-vh;yj"IA`0di

IW`;m{I5ki B. select into隐式游标 !FJ xQf/m

p*h ^al+|;k 代码: tRHdsjn
]*EL:L+|�c(cpS2[.U)r

Q gj.Pi+wI4_ declare
5cS,t{1tf l_tname varchar2(100); 4BS jZu'qHl
begin D&Fu`(_
select tname into l_tname from tab where rownum = 1 ;
+i"V7uwT/c dbms_output.put_line(l_tname); R Yz]5E,g,b
end;
9?V-u9oM7iDMs /
C(l0a�Lhm%} ..
!pX�N M1JRt .. 4D�XA{p0{X$LN

H6~I7f9G-P/lk 动态SQL 的 select into隐式游标
sq0rX T8D#nO;u9o #y Sx"m{K+e�u^P
代码: %e]CU;Q;`#dU
^?eu.pq l~-{/R c @

/a5~eM Qr2G q3NG declare
'M#/UeEXV(Z l_tname varchar2(100); c$p o)rwWDN
l_table_name varchar2(100);
^X1|g l.}!yB l_sql varchar2(200);
H|${'c ^D&i$W begin bz(|HLl,p'[w7KH
l_table_name := 'TAB' ; 2x_IQY*Z
l_sql := 'select tname from '||l_table_name ||' where rownum = 1 ' ; W0sOtY
execute immediate l_sql into l_tname; j)~:}[+/
for i in 1 .. l_tname_array.count loop )B;LO"V(Q!?
    dbms_output.put_line(l_tname_array(i) ); h;X_*Sm#li"{
end loop;
1p%n Lf2wn3n end; ] M!tx@o n
/
EV9gQS"I_ ..
I*?*e6un$v0Bnf` ..

2006-9-27 12:45 小熊
动态SQL 的 select into隐式游标 + Bulk Collect "b,tT&q?W/P

]~al%q 代码: D4G^bX4[.M T

*uxaa+p)c2rp
)R}`8}7KN6M3v9QiR declare ;f3d'r/r [~uO�[
l_tname_array dbms_sql.varchar2_table;
+{ ^X.v)]]'R3F l_table_name varchar2(100); `GeeU
l_sql varchar2(200); ,A!X h)bsAC
begin
-Z L(W+f'T/I]SK/K-i4K l_table_name := 'TAB' ; R#_r e3JsdY"e
l_sql := 'select tname from '||l_table_name ; ;jYP%iZ?
execute immediate l_sql bulk collect into l_tname_array;
-j df0g&JPb8U(U2_ for i in 1 .. l_tname_array.count loop
PA `(m b1M7l2A,M5/     dbms_output.put_line(l_tname_array(i) );
U.l3U;KH5Z:[o z end loop; 8eUg:]O[q8Pu
end; FnU`Kt
/ xHR.FQ*]D#r
.. {/]1Qp+mq0G
.. pSKR~p&l
z%rG$M;Y
C. for .. in 隐式游标
'YpXkuDC &R+i/k'QH+/m;nd3{
for .. in 隐式游标通过loop的开始于结束来控制cursor的Open与Close. 8G:^R2I"Np

j$B&g!EdoY u 代码: 8n[Xfc(Y'|
+Sd4RK}`zw$c I8x
/fFt5v^
begin R/n�R"qtfw1m
for c in (select tname from tab) loop
M4z8s_G0`ZX._ dbms_output.put_line(c.tname);
%l8rqp:Pi+rO end loop; $t{)i?K)I)Z p,I
end; {S#p^X
/
SMo$~;C%^(Kr .. ^YS:X*rQ6g(U1?
..
}1xb8jJYN$y n.J-C&q[�jE

T3TP#YV8} T 2.三种用法的优劣
J r |!mx;W 6Eic;^6sEK9S1C
A. 显式游标
|$["b /me3/+j3t G0o
.M3ObqC[ 优点: :gS+xg I
!CDfYq'sAi$sb6A
·可以用于Bulk Collect的批量处理句式以提高性能 __'zy/S O#p~3o
7v&B-t;n'M%Y
·可以用于动态SQL的游标处理
oh]XBa�dc?
&cL9UM*J 缺点:
akkfbtB^ V0m�N3A/}1[_4yi
·麻烦,需要定义,打开,Fetch,Close一堆代码,增加代码复杂度,从而增加出错的可能性

2006-9-27 12:45 小熊
B. select into隐式游标B
cm^b}0X1s$d(cF
wu/m5e?Z?Y 优点
|b$z3h"nl_w-Hu@:g
"rrG a}/P ·代码量最少
u'u _ r]Y n{(R~,d^ c!j7e
·可以自动Detect 返回数据超过一行或少于一行的错误
5hIX2qPa 7E,I%dW1xhi1~
·可以使用Bulk Collect 批量处理,但是无法使用Limit 关键字
3`Rg8C5eg
[KEK]$^Rj:K 缺点
V8yB*S5Nq/
;]~b~l(A ·如果不使用Bulk Collect 批量处理,仅仅只能用于返回数据正好一行的情况,无法使用于返回数据超过一行或少于一行的环境 !z)?w(`seg9E
mD L+sT,r9d/
·使用Bulk Collect 批量处理时,无法使用limit 关键字,无法处理返回行数太多的情况(不好处理,容易造成PGA过大)
D#qQ7L `%{
"TE{@)E:j C. for .. in 隐式游标
C!WB0wUf3|!j5W
9n FL)^�K0S)yXc 优点 ]oiA%j"rQ6Hq2GB8b$I#Y
1fl H7p$v'M
·代码量远少于显式游标
6fd u"k~w"b N$qFpQ(Y2L@
·代码可读性优于显式游标 C1MqH;x?hn)g
0dD1k/.O l[
·代码的出错可能性也小于显式游标 x[O9FtD]["H$M:G

{c&r^nhl*km 缺点:
k8Zp#XG%D;c
O9J/FNL`#h ·无法用于动态SQL的游标处理
bc4|X(Q7O u VI X)GxI9~RB;N
·在返回行数超过10行的情况下,性能明显不如使用Bulk Collect的显式游标
$h&Ve�KuV/B
9LW&r?j&~5V+FI 在性能对比方面,除非是使用了Bulk Collect,否则,三种方式没有明显性能差距。

2006-9-27 12:46 小熊
3.具体的选择 b yTQ1R"F2|
[email protected]"H
·在返回数据为一行的情况下,尽量使用select into 的隐式游标 5_p,Y3wzd8Q*Z)u2]"Y

J1a8P5K2B ·返回0行或者<几十行的情况下,使用for .. in 隐式游标 e%J2oHf&a(T.s}
S8z(k^2W%B1Ce [}e
·或者在返回行稍多,但是不关心Fetch性能的情况下,也可考虑用for .. in 隐式游标 O+u8dr.n _H
-Lb[@:A h{
·返回10行-100行(一个很随意选择的经验值,可以自己根据情况设定),而且关心Fetch性能的情况下,可以使用select into 的隐式游标+Bulk collect ,在获得性能提升的情况下,代码量也不会增加太多。 C,`j&P[~S
6kD#eJV3F;|-]
·返回行数很多,> 100, 应选用显示游标+Bulk collect ,以获得较高的Fetch 性能,同时不至于使用太大的PGA内存。
9/A3w#]-D R&p-h6vZv "c Pt![`Q`x6N`'N9Q
·如国使用动态SQL, 则根据select list (column list) 是否固定,如果固定,仍然可以考虑使用select into 的隐式游标+动态SQL的方式。当然,仍然需要考虑返回行数的问题。
b#q3B.P r&}GH$S mR 8|F8g~*o P.}
·如果select list (column list) 不固定,则只好使用显式游标
(nuz/H3Xq0YPA@
0P$Y7j })Ww^,| ·或者动态语句返回行数太多,必须用limit,那么也只好用显式游标了。

你可能感兴趣的:(PL/SQL 中如何正确选择游标类型)