在試圖增加序列的NEXTVAL的時候,無意中發(fā)現(xiàn)了這個問題。
首先還是看看現(xiàn)象:
SQL> CREATE SEQUENCE SEQ_TEST;
序列已創(chuàng)建。
SQL> SELECT SEQ_TEST.NEXTVAL FROM DUAL;
NEXTVAL
1 SQL> BEGIN
2 FOR I IN 1..1000 LOOP
3 EXECUTE IMMEDIATE 'SELECT SEQ_TEST.NEXTVAL FROM DUAL';
4 END LOOP;
5 END;
6 /
PL/SQL 過程已成功完成。
SQL> SELECT SEQ_TEST.NEXTVAL FROM DUAL;
NEXTVAL
1 可以看到,序列SEQ_TEST的NEXTVAL并不像想象中的提高了1000,而給人的感覺似乎根本沒有執(zhí)行。
避免的方法也簡單,只需要添加INTO語句:
SQL> DECLARE
2 TYPE T_ID IS TABLE OF NUMBER;
3 V_ID T_ID;
4 BEGIN
5 FOR I IN 1..1000 LOOP
6 EXECUTE IMMEDIATE 'SELECT SEQ_TEST.NEXTVAL FROM DUAL'
7 BULK COLLECT INTO V_ID;
8 END LOOP;
9 END;
10 /PL/SQL 過程已成功完成。SQL> SELECT SEQ_TEST.NEXTVAL FROM DUAL;
NEXTVAL
1003
產(chǎn)生這種情況有兩種可能,一是由于Oracle發(fā)現(xiàn)動態(tài)SQL的執(zhí)行沒有INTO語句,不需要返回結(jié)果,因此根本沒有執(zhí)行;二是Oracle只是打開游標,并沒有FETCH數(shù)據(jù),因此造成了序列的值沒有發(fā)生變化。
最后通過一個測試檢驗一下,到底是哪種情況造成了上面的現(xiàn)象:
SQL> CREATE OR REPLACE FUNCTION F_TEST RETURN NUMBER AS
2 BEGIN
3 DBMS_LOCK.SLEEP(10);
4 RETURN 0;
5 END;
6 /函數(shù)已創(chuàng)建。
SQL> SET TIMING ON
SQL> BEGIN
2 EXECUTE IMMEDIATE 'SELECT F_TEST FROM DUAL';
3 END;
4 / PL/SQL 過程已成功完成。
已用時間: 00: 00: 00.10
SQL> DECLARE
2 V_ID NUMBER;
3 BEGIN
4 EXECUTE IMMEDIATE 'SELECT F_TEST FROM DUAL' INTO V_ID;
5 END;
6 / PL/SQL 過程已成功完成。
已用時間: 00: 00: 10.29
通過對比就可以發(fā)現(xiàn),如果缺少INTO語句,那么動態(tài)SQL就不會執(zhí)行。
首先還是看看現(xiàn)象:
SQL> CREATE SEQUENCE SEQ_TEST;
序列已創(chuàng)建。
SQL> SELECT SEQ_TEST.NEXTVAL FROM DUAL;
NEXTVAL
1 SQL> BEGIN
2 FOR I IN 1..1000 LOOP
3 EXECUTE IMMEDIATE 'SELECT SEQ_TEST.NEXTVAL FROM DUAL';
4 END LOOP;
5 END;
6 /
PL/SQL 過程已成功完成。
SQL> SELECT SEQ_TEST.NEXTVAL FROM DUAL;
NEXTVAL
1 可以看到,序列SEQ_TEST的NEXTVAL并不像想象中的提高了1000,而給人的感覺似乎根本沒有執(zhí)行。
避免的方法也簡單,只需要添加INTO語句:
SQL> DECLARE
2 TYPE T_ID IS TABLE OF NUMBER;
3 V_ID T_ID;
4 BEGIN
5 FOR I IN 1..1000 LOOP
6 EXECUTE IMMEDIATE 'SELECT SEQ_TEST.NEXTVAL FROM DUAL'
7 BULK COLLECT INTO V_ID;
8 END LOOP;
9 END;
10 /PL/SQL 過程已成功完成。SQL> SELECT SEQ_TEST.NEXTVAL FROM DUAL;
NEXTVAL
1003
產(chǎn)生這種情況有兩種可能,一是由于Oracle發(fā)現(xiàn)動態(tài)SQL的執(zhí)行沒有INTO語句,不需要返回結(jié)果,因此根本沒有執(zhí)行;二是Oracle只是打開游標,并沒有FETCH數(shù)據(jù),因此造成了序列的值沒有發(fā)生變化。
最后通過一個測試檢驗一下,到底是哪種情況造成了上面的現(xiàn)象:
SQL> CREATE OR REPLACE FUNCTION F_TEST RETURN NUMBER AS
2 BEGIN
3 DBMS_LOCK.SLEEP(10);
4 RETURN 0;
5 END;
6 /函數(shù)已創(chuàng)建。
SQL> SET TIMING ON
SQL> BEGIN
2 EXECUTE IMMEDIATE 'SELECT F_TEST FROM DUAL';
3 END;
4 / PL/SQL 過程已成功完成。
已用時間: 00: 00: 00.10
SQL> DECLARE
2 V_ID NUMBER;
3 BEGIN
4 EXECUTE IMMEDIATE 'SELECT F_TEST FROM DUAL' INTO V_ID;
5 END;
6 / PL/SQL 過程已成功完成。
已用時間: 00: 00: 10.29
通過對比就可以發(fā)現(xiàn),如果缺少INTO語句,那么動態(tài)SQL就不會執(zhí)行。