• 提高性能的BULK COLLECT语句和FORALL语句 IN PLSQL


    提高性能的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;
    复制代码
  • 相关阅读:
    myeclipse中如何自动生成hibernate得POJO和hbm.xml文件
    解决“List is a raw type. References to generic type List”提示的问题
    Struts2文件目录结构
    DropDownlist 选中
    js获取网站根路径(站点及虚拟目录)
    HTML 特殊字符全集
    抽象类和接口的区别
    有关onpropertychange事件
    JS 括号使用分析
    Field.Store ,ANALYZED备忘
  • 原文地址:https://www.cnblogs.com/Jeffrey-xu/p/5057715.html
Copyright © 2020-2023  润新知