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
loopnt]'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
beginD&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 beginbz(|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^
beginR/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,那麼也只好用顯式遊標了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章