原创文章,转载请注明出处:http://blog.itpub.net/30168575/viewspace-1465287/
通过 FORALL 加速 DML
BULK COLLECT 对查询加速,而 FORALL 会对增删改以及合并加速(Oracle 11g 才支持 FORALL 的合并)。FORALL 告诉PL/SQL引擎要先把一个或者多个集合的所有成员都绑定到SQL语句中,然后再把语句发送给SQL引擎。
FORALL 语句的语法
虽然 FORALL 语句带有一个迭代模式,但它不是一个 FOR 循环。语法如下:
FORALL index_row IN
[ lower_bound .. upper_bound |
INDICES OF indexing_collection |
VALUES OF indexing_collection ]
[ SAVE EXCEPTIONS ]
sql_statements;
其中:
index_row 是一个整数,由Oracle隐式声明,并且被定义做集合的索引值。
lower_bound 操作开始的索引值(行或者是集合元素)
upper_bound 操作结束的索引值(行或者是集合元素)
sql_statements 将对每一个元素执行的SQL语句
indexing_collection 这是一个pl/sql集合,是一个指向sql_statements所使用的绑定数组的索引的集合;INDICES OF 和 VALUES OF 是从Oracle 10g才有的。
SAVE EXCEPTIONS 这是一个可选的子句,告诉 FORALL 处理全部行,不过把发生的任何异常都保存下来。
测试表中有超过100万数据,处理逻辑为简单的从一个表复制数据到另一个表
-- 测试表:
测试逻辑代码单元
测试过程
测试两种方法的性能
SQL> SET timing ON
SQL> BEGIN
2 my_test.copydata_test;
3 END;
4 /
PL/SQL procedure successfully completed
Executed in 608.966 seconds
SQL> ROLLBACK;
Rollback complete
Executed in 81.277 seconds
SQL> BEGIN
2 my_test.copydata_test_forall;
3 END;
4 /
PL/SQL procedure successfully completed
Executed in 43.665 seconds
SQL> ROLLBACK;
Rollback complete
Executed in 4.477 seconds
-- 测试结果:
-- 很容易看出,使用游标 FOR 循环时,处理耗时608.966s,而改用了 FORALL 之后,处理时间减少到 43.665s。这个提升是非常值得尝试的。
FORALL 语句将 DML 批量从 PL/SQL引擎提交给 SQL引擎,从而减少了程序执行过程中上下文切换的次数。而上下文切换的开销是十分昂贵的。
通过 FORALL 加速 DML
BULK COLLECT 对查询加速,而 FORALL 会对增删改以及合并加速(Oracle 11g 才支持 FORALL 的合并)。FORALL 告诉PL/SQL引擎要先把一个或者多个集合的所有成员都绑定到SQL语句中,然后再把语句发送给SQL引擎。
FORALL 语句的语法
虽然 FORALL 语句带有一个迭代模式,但它不是一个 FOR 循环。语法如下:
FORALL index_row IN
[ lower_bound .. upper_bound |
INDICES OF indexing_collection |
VALUES OF indexing_collection ]
[ SAVE EXCEPTIONS ]
sql_statements;
其中:
index_row 是一个整数,由Oracle隐式声明,并且被定义做集合的索引值。
lower_bound 操作开始的索引值(行或者是集合元素)
upper_bound 操作结束的索引值(行或者是集合元素)
sql_statements 将对每一个元素执行的SQL语句
indexing_collection 这是一个pl/sql集合,是一个指向sql_statements所使用的绑定数组的索引的集合;INDICES OF 和 VALUES OF 是从Oracle 10g才有的。
SAVE EXCEPTIONS 这是一个可选的子句,告诉 FORALL 处理全部行,不过把发生的任何异常都保存下来。
测试表中有超过100万数据,处理逻辑为简单的从一个表复制数据到另一个表
-- 测试表:
点击(此处)折叠或打开
- DROP TABLE data_test;
- CREATE TABLE data_test(
- hi_card_nbr number,
- hi_card_str VARCHAR2(4000),
- hi_card_ts Timestamp
- );
- /
- DECLARE
- counter NUMBER;
- BEGIN
- EXECUTE IMMEDIATE \'TRUNCATE TABLE data_test\';
- INSERT INTO data_test
- SELECT t.cpu_time, t.sql_text, t.first_load_time FROM v$sql t
- UNION ALL
- SELECT t.object_id, t.object_name, t.timestamp FROM DBA_objects t;
-
- counter := SQL%ROWCOUNT;
-
- WHILE counter < 1000000 LOOP
- INSERT INTO data_test SELECT * FROM data_test;
- counter := counter + SQL%ROWCOUNT;
- END LOOP;
- END;
- /
- COMMIT;
测试逻辑代码单元
点击(此处)折叠或打开
- CREATE OR REPLACE PACKAGE my_test IS
- PROCEDURE copydata_test;
- PROCEDURE copydata_test_forall;
- END my_test;
- /
- CREATE OR REPLACE PACKAGE BODY my_test IS
- PROCEDURE copydata_test IS
- CURSOR cur IS
- SELECT * from data_test;
- BEGIN
- FOR rec IN cur LOOP
- INSERT INTO data_test_into VALUES(rec.hi_card_nbr, rec.hi_card_str, rec.hi_card_ts);
- END LOOP;
- END copydata_test;
-
-
-
-
- PROCEDURE copydata_test_forall IS
- CURSOR cur IS
- SELECT * from data_test;
- TYPE rec_t IS TABLE OF cur%ROWTYPE INDEX BY binary_integer;
- rec rec_t;
- BEGIN
- OPEN cur;
- LOOP
- FETCH cur BULK COLLECT INTO rec LIMIT 100;
- FORALL indx IN rec.FIRST .. rec.LAST
- INSERT INTO data_test_into VALUES rec(indx);
-
-
- EXIT WHEN cur%NOTFOUND;
- END LOOP;
- CLOSE cur;
- END copydata_test_forall;
- END my_test;
- /
测试过程
点击(此处)折叠或打开
- -- 先调用两遍预热缓存
- BEGIN
- my_test.copydata_test;
- ROLLBACK;
- my_test.copydata_test_forall;
- ROLLBACK;
- END;
- /
- BEGIN
- my_test.copydata_test;
- ROLLBACK;
- my_test.copydata_test_forall;
- ROLLBACK;
- END;
- /
- ROLLBACK;
测试两种方法的性能
SQL> SET timing ON
SQL> BEGIN
2 my_test.copydata_test;
3 END;
4 /
PL/SQL procedure successfully completed
Executed in 608.966 seconds
SQL> ROLLBACK;
Rollback complete
Executed in 81.277 seconds
SQL> BEGIN
2 my_test.copydata_test_forall;
3 END;
4 /
PL/SQL procedure successfully completed
Executed in 43.665 seconds
SQL> ROLLBACK;
Rollback complete
Executed in 4.477 seconds
-- 测试结果:
-- 很容易看出,使用游标 FOR 循环时,处理耗时608.966s,而改用了 FORALL 之后,处理时间减少到 43.665s。这个提升是非常值得尝试的。
FORALL 语句将 DML 批量从 PL/SQL引擎提交给 SQL引擎,从而减少了程序执行过程中上下文切换的次数。而上下文切换的开销是十分昂贵的。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30168575/viewspace-1465287/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/30168575/viewspace-1465287/