PLSQL NOTE--------提高性能的BULK COLLECT语句和FORALL语句

提高性能的BULK COLLECT语句和FORALL语句

pl/sql向sql引擎发送sql语句执行,然后SQL向pl/sql 返回结果数据。可以使用pl/sql的大批量sql特性来降低sql和pl /sql之间的通信开销。FORALL语句将INSERT或UPDATE或DELETE批次处理,BULK COLLECT子句带回批结果。如果,DML语句影响四个或更多个数据库行,使用bulk sql(批量SQL)可以显著提高性能。

1.FORALL语句的使用

但是,FORALL语句只能重复单独一条 DML语句。 例子:FORALL语句一次性把三条DELETE 语句发给SQL引擎:

 1  CREATE TABLE employees_temp AS SELECT * FROM employees;
 2  DECLARE
 3     TYPE NumList IS VARRAY(20) OF NUMBER;
 4     depts NumList := NumList(10, 30, 70);  -- department numbers
 5  BEGIN
 6     FORALL i IN depts.FIRST..depts.LAST
 7        DELETE FROM employees_temp WHERE department_id = depts(i);
 8     COMMIT;
 9  END;
10  /

我们可以通过下面的例子来比较FOR语句和FORALL语句的执行时间:

 1  CREATE TABLE parts1 (pnum INTEGER, pname VARCHAR2(15));
 2  CREATE TABLE parts2 (pnum INTEGER, pname VARCHAR2(15));
 3  DECLARE
 4    TYPE NumTab IS TABLE OF parts1.pnum%TYPE INDEX BY PLS_INTEGER;
 5    TYPE NameTab IS TABLE OF parts1.pname%TYPE INDEX BY PLS_INTEGER;
 6    pnums  NumTab;
 7    pnames NameTab;
 8    iterations CONSTANT PLS_INTEGER := 500;
 9    t1 INTEGER;
10    t2 INTEGER;
11    t3 INTEGER;
12  BEGIN
13    FOR j IN 1..iterations LOOP  -- load index-by tables
14       pnums(j) := j;
15       pnames(j) := ‘Part No. ‘ || TO_CHAR(j);
16    END LOOP;
17    t1 := DBMS_UTILITY.get_time;
18    FOR i IN 1..iterations LOOP  -- use FOR loop
19       INSERT INTO parts1 VALUES (pnums(i), pnames(i));
20    END LOOP;
21    t2 := DBMS_UTILITY.get_time;
22    FORALL i IN 1..iterations  -- use FORALL statement
23       INSERT INTO parts2 VALUES (pnums(i), pnames(i));
24    t3 := DBMS_UTILITY.get_time;
25    DBMS_OUTPUT.PUT_LINE(‘Execution Time (secs)‘);
26    DBMS_OUTPUT.PUT_LINE(‘---------------------‘);
27    DBMS_OUTPUT.PUT_LINE(‘FOR loop: ‘ || TO_CHAR((t2 - t1)/100));
28    DBMS_OUTPUT.PUT_LINE(‘FORALL:   ‘ || TO_CHAR((t3 - t2)/100));
29    COMMIT;
30  END;
31  /
32  Execution Time (secs)
33  ---------------------
34  FOR loop: .02
35  FORALL:   0

由此,我们可以看出使用FORALL语句更快。

2.使用部分索引的FORALL语句(Part of a Collection)

 此外,我们可以只使用条件集合的部分用于FORALL条件。如:

 1  CREATE TABLE employees_temp AS SELECT * FROM employees;
 2  DECLARE
 3     TYPE NumList IS VARRAY(10) OF NUMBER;
 4     depts NumList := NumList(5,10,20,30,50,55,57,60,70,75);
 5  BEGIN
 6     FORALL j IN 4..7  -- use only part of varray
 7        DELETE FROM employees_temp WHERE department_id = depts(j);
 8     COMMIT;
 9  END;
10  /

3.使用非连续的稀疏索引的FORALL语句(Non-Consecutive Index Values)
  同样,我们也可以使用非连续的index value(索引值)作为条件,这需要使用INDICES OF子句来处理。

 1  -- Create empty tables to hold order details
 2  CREATE TABLE valid_orders (cust_name VARCHAR2(32), amount NUMBER(10,2));
 3  CREATE TABLE big_orders AS SELECT * FROM valid_orders WHERE 1 = 0;
 4  CREATE TABLE rejected_orders AS SELECT * FROM valid_orders WHERE 1 = 0;
 5  DECLARE
 6  -- Make collections to hold a set of customer names and order amounts.
 7     SUBTYPE cust_name IS valid_orders.cust_name%TYPE;
 8     TYPE cust_typ IS TABLE OF cust_name;
 9     cust_tab cust_typ;
10     SUBTYPE order_amount IS valid_orders.amount%TYPE;
11     TYPE amount_typ IS TABLE OF NUMBER;
12     amount_tab amount_typ;
13  -- Make other collections to point into the CUST_TAB collection.
14     TYPE index_pointer_t IS TABLE OF PLS_INTEGER;
15     big_order_tab index_pointer_t := index_pointer_t();
16     rejected_order_tab index_pointer_t := index_pointer_t();
17     PROCEDURE setup_data IS BEGIN
18  -- Set up sample order data, including some invalid orders and some ‘big‘ orders.
19       cust_tab := cust_typ(‘Company1‘,‘Company2‘,‘Company3‘,‘Company4‘,‘Company5‘);
20       amount_tab := amount_typ(5000.01, 0, 150.25, 4000.00, NULL);
21     END;
22  BEGIN
23     setup_data();
24     DBMS_OUTPUT.PUT_LINE(‘--- Original order data ---‘);
25     FOR i IN 1..cust_tab.LAST LOOP
26       DBMS_OUTPUT.PUT_LINE(‘Customer #‘ || i || ‘, ‘ || cust_tab(i) || ‘: $‘ ||
27                             amount_tab(i));
28     END LOOP;
29  -- Delete invalid orders (where amount is null or 0).
30     FOR i IN 1..cust_tab.LAST LOOP
31       IF amount_tab(i) is null or amount_tab(i) = 0 THEN
32          cust_tab.delete(i);
33          amount_tab.delete(i);
34       END IF;
35     END LOOP;
36     DBMS_OUTPUT.PUT_LINE(‘--- Data with invalid orders deleted ---‘);
37     FOR i IN 1..cust_tab.LAST LOOP
38       IF cust_tab.EXISTS(i) THEN
39         DBMS_OUTPUT.PUT_LINE(‘Customer #‘ || i || ‘, ‘ || cust_tab(i) || ‘: $‘ ||
40                               amount_tab(i));
41        END IF;
42     END LOOP;
43  -- Because the subscripts of the collections are not consecutive, use
44  -- FORALL...INDICES OF to iterate through the actual subscripts,
45  -- rather than 1..COUNT
46     FORALL i IN INDICES OF cust_tab
47       INSERT INTO valid_orders(cust_name, amount)
48          VALUES(cust_tab(i), amount_tab(i));
49  -- Now process the order data differently
50  -- Extract 2 subsets and store each subset in a different table
51     setup_data(); -- Initialize the CUST_TAB and AMOUNT_TAB collections again.
52     FOR i IN cust_tab.FIRST .. cust_tab.LAST LOOP
53       IF amount_tab(i) IS NULL OR amount_tab(i) = 0 THEN
54         rejected_order_tab.EXTEND; -- Add a new element to this collection
55  -- Record the subscript from the original collection
56         rejected_order_tab(rejected_order_tab.LAST) := i;
57       END IF;
58       IF amount_tab(i) > 2000 THEN
59          big_order_tab.EXTEND; -- Add a new element to this collection
60  -- Record the subscript from the original collection
61          big_order_tab(big_order_tab.LAST) := i;
62       END IF;
63     END LOOP;
64  -- Now it‘s easy to run one DML statement on one subset of elements,
65  -- and another DML statement on a different subset.
66     FORALL i IN VALUES OF rejected_order_tab
67       INSERT INTO rejected_orders VALUES (cust_tab(i), amount_tab(i));
68     FORALL i IN VALUES OF big_order_tab
69       INSERT INTO big_orders VALUES (cust_tab(i), amount_tab(i));
70     COMMIT;
71  END;
72  /
73  -- Verify that the correct order details were stored
74  SELECT cust_name "Customer", amount "Valid order amount" FROM valid_orders;
75  SELECT cust_name "Customer", amount "Big order amount" FROM big_orders;
76  SELECT cust_name "Customer", amount "Rejected order amount" FROM rejected_orders;
时间: 2024-07-28 17:21:21

PLSQL NOTE--------提高性能的BULK COLLECT语句和FORALL语句的相关文章

Oracle数据库之FORALL与BULK COLLECT语句

   我们再来看一下PL/SQL块的执行过程:当PL/SQL运行时引擎处理一块代码时,它使用PL/SQL引擎来执行过程化的代码,而将SQL语句发送给SQL引擎来执行:SQL引擎执行完毕后,将结果再返回给PL/SQL引擎.这种在PL/SQL引擎和SQL引擎之间的交互,称为上下文交换(context switch).每发生一次交换,就会带来一定的额外开销. FORALL,用于增强PL/SQL引擎到SQL引擎的交换. BULK COLLECT,用于增强SQL引擎到PL/SQL引擎的交换.(前面我们已经

FORALL与BULK COLLECT是实现批量SQL

2014年11月20日,星期四 更新 1. 示例1 declare/*    type card_rec_type is record    ( dn_no channel.dn_no%type,        channel_id channel.channel_id%type);    type nested_card_type is table of card_rec_type;    card_tab nested_card_type; */    cursor card_rec is 

ORACLE批量绑定FORALL与BULK COLLECT

FORALL与BULK COLLECT的使用方法: 1.使用FORALL比FOR效率高,因为前者只切换一次上下文,而后者将是在循环次数一样多个上下文间切换. 2.使用BLUK COLLECT一次取出一个数据集合,比用游标条取数据效率高,尤其是在网络不大好的情况下.但BLUK COLLECT需要大量内存. 例子: Sql代码   create table test_forall ( user_id number(10), user_name varchar2(20)); select into 中

PLSQL_性能优化系列11_Oracle Bulk Collect

(1).SQL DECLARE i NUMBER; TYPE c_type_wip_entity IS TABLE OF wip_entities%ROWTYPE; c_wip_entity c_type_wip_entity; BEGIN SELECT * BULK COLLECT INTO c_wip_entity FROM wip_entities WHERE wip_entity_id IN (2363, 2462); FOR i IN 1 .. c_wip_entity.COUNT L

FORALL和BULK COLLECT

参考:http://www.cnblogs.com/hellokitty1/p/4584333.html 用户在通过PLSQL编写程序时,PLSQL通常会在操作上进行交互,当用户通过PLSQL执行一条更新语句时,SQL会将更新后的数据返回给PLSQL,这样用户才可以在PLSQL之中取得更新后的数据,但是如果在PLSQL之中要进行大量的数据操作时,这种方式就会使程序执行性能大大降低. 例如:通过PLSQL执行多行数据更新 1 DECLARE 2 TYPE emp_array_type IS VAR

oracle常用的复合数据类型 : BULK COLLECT(成批聚合类型)和数组集合type类型is table of 表%rowtype index by binary_integer

例1: 批量 查询部门号为 "10" 号的并把它们打印出来 . DECLARE TYPE emp_table_type IS TABLE OF my_emp%ROWTYPE INDEX BY BINARY_INTEGER; v_emp_table emp_table_type; BEGIN SELECT * BULK COLLECT INTO v_emp_table FROM my_emp WHERE deptno=&deptno; FOR i IN 1..v_emp_tabl

oracle学习之bulk collect用法

Oracle8i中首次引入了Bulk Collect特性,该特性可以让我们在PL/SQL中能使用批查询,批查询在某些情况下能显著提高查询效率. 采用bulk collect可以将查询结果一次性地加载到collections中. 而不是通过cursor一条一条地处理. 可以在select into,fetch into,returning into语句使用bulk collect. 注意在使用bulk collect时,所有的into变量都必须是collections <span style=&quo

SQL中使用WITH AS提高性能,使用公用表表达式(CTE)简化嵌套SQL

一.WITH AS的含义     WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到.有的时候,是为了让SQL语句的可读性更高些,也有可能是在UNION ALL的不同部分,作为提供数据的部分. 特别对于UNION ALL比较有用.因为UNION ALL的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太高,所以可以使用WITH AS短语,则只要执行一遍即可.如果WITH AS短语所定

EF提高性能

实体框架 5 性能注意事项 作者:David Obando.Eric Dettinger 等 发布时间:2012 年 4 月 1.简介 对象关系映射框架是一种在面向对象的应用程序中提供数据访问抽象的便捷方式.对于 .NET 应用程序,Microsoft 推荐的 O/RM 是实体框架.但任何抽象都要考虑性能. 本白皮书旨在介绍在使用实体框架开发应用程序时的性能注意事项,使开发人员了解能够影响性能的实体框架内部算法,以及提供有关进行调查及在使用实体框架的应用程序中提高性能的提示.网络上有大量很好的有