世風之狡詐多端,到底忠厚人顛撲不破; 末俗以繁華相尚,終覺冷淡處趣味彌長。sql
BULK COLLECT運用併發
在遊標中運用oop
declare 測試
cursor C_CUR is SELECT * FROM T_TEST;fetch
TYPE T_TYPE IS TABLE OF T_TEST%ROWTYPE;----須要定義一個數據記錄的類型spa
C_REC T_TYPE;it
begin for循環
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速度,能夠看我以前對併發作的測試.
最後送看文章的小夥伴一句話
乾坤未定,你我皆是黑馬.