oracle 优化之批量处理bulk correct 和 forall
世風之狡詐多端,到底忠厚人顛撲不破; 末俗以繁華相尚,終覺冷淡處趣味彌長。
BULK? ?COLLECT運用
在游標中運用
declare?
cursor C_CUR is SELECT * FROM? T_TEST;
TYPE?T_TYPE IS TABLE OF??T_TEST%ROWTYPE;----需要定義一個數據記錄的類型
C_REC? T_TYPE;
begin?
open?C_CUR ;
loop
? FETCH??C_CUR BULK?COLLECT INTO?C_REC LIMIT 5000;?
?EXIT WHEN? C_REC.COUNT=0; ---這個地方不可以用? ?exit when?C_CUR%notfound 會導致少記錄? 如果用的話可以在循環結束的時候用,這是區別于普通游標的一個關鍵地方
?for I in?C_REC.first..C_REC.LAST?
?LOOP
?INSERT INTO MXQ(ID,NAME)? VALUES (C_REC(I).ID,C_REC(I).NAME);
UPDATE? MXQ? SET ID=C_REC(I).ID WHERE??NAME=C_REC(I).NAME;
END LOOP;
EXIT? WHEN?C_CUR%NOTFOUND;--粉色標明的地方 可以任意選擇一個退出循環
end loop;
close?C_CUR;
end;
forall 運用
forall也是一個集合提取 它不同于for循環的地方在于
1.它不是一個循環 不用接loop 和 end loop
?2.forall 后面只能跟一個dml語句.否則會報錯.
綜合運用BULK CORRECT 和?forall之后以上sql核心部分可以改寫成這樣?
loop
FETCH??C_CUR BULK?COLLECT INTO?C_REC LIMIT 5000;?
?EXIT WHEN? C_REC.COUNT=0;?
?forall I in?C_REC.first..C_REC.LAST?
INSERT INTO MXQ(ID,NAME)? VALUES (C_REC(I).ID,C_REC(I).NAME);----forall 后面只能跟一個dml語句
forall I in?C_REC.first..C_REC.LAST?
UPDATE? MXQ? SET ID=C_REC(I).ID WHERE??NAME=C_REC(I).NAME;
end loop;
關于fetch bulk collect into 游標記錄類型的聲明
聲明一個表中的記錄
DECLARE
CURSOR C_CUR IS SELECT * FROM TAB_TEST;
TYPE C_TYPE IS TABLE OF?TAB_TEST%ROWTYPE;
C_REC?C_TYPE;
聲明多個表中的記錄
DECLARE
CURSOR C_CUR IS SELECT A.ROWID,B.NAME FROM TAB_TEST_1 A,TAB_TEST_2 B WHERE A.ID=B.ID;
TYPE? C_TYPE_REC IS RECORD (ROWID? ? VARCHAR2(32),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?NAME? ? ? TAB_TEST_2%TYPE );----因為是兩個表中的字段所以需要聲明一個記錄類型record包含這兩個表的字段
TYPE? C_TYPE IS TABLE OF?C_TYPE_REC;----把類型聲明成剛才那個記錄的類型,? 注意不需要%ROWTYPE? ?因為C_TYPE_REC已經是一個記錄類型了
C_REC?C_TYPE;
測試 效率? 數據270萬 環境11g
用BULK COLLECT? 和??forall?
寫法一
DECLARE?
CURSOR C_CUR IS SELECT A.ROWID FROM mxq A;
TYPE C_TYPE IS TABLE OF C_CUR%ROWTYPE;
C_REC C_TYPE;
BEGIN
OPEN C_CUR;
LOOP
FETCH C_CUR BULK COLLECT INTO C_REC LIMIT 10000;
EXIT WHEN C_REC.count=0;
FORALL I IN C_REC.FIRST..C_REC.LAST
UPDATE mxq A SET A.BEIZHU=(SELECT BEIZHU FROM mxq_1 B WHERE A.SNAME=B.SNAME ) WHERE A.ROWID=C_REC(I).ROWID;
commit;
END LOOP;
CLOSE C_CUR;
END; 222秒
寫法二
DECLARE
CURSOR C_CUR IS SELECT A.ROWID,B.BEIZHU FROM mxq A,mxq_1 B WHERE A.SNAME=B.SNAME;
TYPE C_TYPE IS TABLE OF C_CUR%ROWTYPE;
C_REC C_TYPE;
BEGIN
OPEN C_CUR;
LOOP
FETCH C_CUR BULK COLLECT INTO C_REC LIMIT 10000;
EXIT WHEN C_REC.count=0;
FORALL I IN C_REC.FIRST..C_REC.LAST
UPDATE mxq A SET A.BEIZHU=C_REC(I).BEIZHU WHERE A.ROWID=C_REC(I).ROWID;
commit;
END LOOP;
CLOSE C_CUR;
END; 267秒
這兩個寫法加載進游標的數據記錄不一樣經過測試發現 差距不大.
用兩種寫法分別使用批處理和不使用批處理
不用BULK COLLECT? 和??forall?
寫法一
?DECLARE?
CURSOR C_CUR IS SELECT A.ROWID FROM mxq A;
C_REC C_CUR%ROWTYPE;
BEGIN
OPEN C_CUR;
LOOP
FETCH C_CUR INTO C_REC ;
EXIT WHEN C_CUR%NOTFOUND;
UPDATE mxq A SET A.BEIZHU=(SELECT BEIZHU FROM mxq_1 B WHERE A.SNAME=B.SNAME ) WHERE A.ROWID=C_REC.ROWID;
commit;
END LOOP;
CLOSE C_CUR;
END;1000秒
?寫法二
DECLARE
CURSOR C_CUR IS SELECT A.ROWID,B.BEIZHU FROM mxq A,mxq_1 B WHERE A.SNAME=B.SNAME;
C_REC C_CUR%ROWTYPE;
BEGIN
OPEN C_CUR;
LOOP
FETCH C_CUR INTO C_REC ;
EXIT WHEN C_CUR%NOTFOUND;
UPDATE mxq A SET A.BEIZHU=C_REC.BEIZHU WHERE A.ROWID=C_REC.ROWID;
commit;
END LOOP;
CLOSE C_CUR;
END;804秒
不用批處理的dml語句 寫法二比寫法一快的明顯一些快了200秒.
總結
1.批處理比單條處理快了大概4倍.
2.sql寫法也一定程度上決定了dml的速度.
3可以用并發來提高dml速度,可以看我之前對并發做的測試.
最后送看文章的小伙伴一句話
乾坤未定,你我皆是黑馬.
轉載于:https://www.cnblogs.com/throughRiversandLake/p/10894482.html
總結
以上是生活随笔為你收集整理的oracle 优化之批量处理bulk correct 和 forall的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Importance Sampling
- 下一篇: 邯郸耘农智慧农业科技有限公司怎么样?