oracle 優化之批量處理bulk correct 和 forall

世風之狡詐多端,到底忠厚人顛撲不破; 末俗以繁華相尚,終覺冷淡處趣味彌長。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速度,能夠看我以前對併發作的測試.

最後送看文章的小夥伴一句話

乾坤未定,你我皆是黑馬.

相關文章
相關標籤/搜索