Oracle forall bulk collect批量數據更新


對於數據量較大的插入操作可采用此種方法操作,注意:

  1. limit減少內存占用,如果數據量較大一次性全部加載到內存中,對PGA來說壓力太大,可采用limit的方法一次加載一定數量的數據,建議值通常為1000。使用limit時注意,循環的時候如果用while cursor_name%found loop,對於最后一次fetch的數據量不足設定值1000,%found條件就會不成立。示例使用v_oid_lst.count > 0作為判斷條件。
  2. 在寫plsql代碼塊,定義數值變量時,建議采用pls_integer類型,或者simple_integer類型,區別:

    oracle9i之前有binary_integer類型,和11g中引入的pls_integer數值范圍相同:-2147483647~+2147483647,但pls_integer有更高的性能。兩者性能均優於number類型。

    Oracle中也引入了simple_integer類型,不過不能包含null值,范圍:-2147483648~2147483647,性能優於pls_integer。

  3. 使用ref cursor。
  4. 使用綁定變量。
  5. 自定義table類型。
  6. Bulk collect into加載到內存中,處理完業務邏輯后forall批量插入到數據表中。
  7. Forall可以使用returning bulk collect into,且可使用sql%rowcount返回其更新行數。
  8. type numbers is table of number index by binary_integer/pls_integer/simple_integer; 其作用是:

    加了"index by binary_integer "后,numbers類型的下標就是自增長,numbers類型在插入元素時,不需要初始化,不需要每次extend增加一個空間。

    而如果沒有這句話"index by binary_integer",那就得要顯示對初始化,且每插入一個元素到numbers類型的table中時,都需要先extend。

  9. 關於table、record、varray的詳細使用,參考:http://blog.csdn.net/liangweiwei130/article/details/38223319

示例代碼:

 SQL Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

  

declare
  type v_t_oid is table of ljz_all_objects.object_id%type;
  v_oid_lst v_t_oid;
  type v_t_cur_oid is ref cursor;
  v_cur_oid v_t_cur_oid;
  v_cnt     simple_integer := 1000;
begin
  open v_cur_oid for 'select object_id from ljz_all_objects where object_id>:1'
    using 1;
  fetch v_cur_oid bulk collect
    into v_oid_lst limit v_cnt;
  while v_oid_lst.count > 0 loop
    for i in 1 .. v_oid_lst.count loop
      --
業務處理邏輯
      v_oid_lst(i) := v_oid_lst(i) + 1;
    end loop;
    forall i in v_oid_lst.first .. v_oid_lst.last
      insert into ljz_test (col) values (v_oid_lst(i));
    fetch v_cur_oid bulk collect
      into v_oid_lst limit 1000;
    commit;
  end loop;
  close v_cur_oid;
end;

定義record類型,多列插入:

 SQL Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

  

declare
  type v_t_r is record(
    object_id   ljz_all_objects.object_id%type,
    object_name ljz_all_objects.object_name%type);
  v_r v_t_r;
  type v_t_oid is table of v_t_r index by simple_integer;
  v_oid_lst  v_t_oid;
  v_oid_lst1 v_t_oid;
  type v_t_cur_oid is ref cursor;
  v_cur_oid v_t_cur_oid;
  v_cnt     simple_integer := 1000;
begin
  open v_cur_oid for 'select object_id,object_name from ljz_all_objects where object_id>:1'
    using 1;
  fetch v_cur_oid bulk collect
    into v_oid_lst limit v_cnt;
  while v_oid_lst.count > 0 loop
    for i in 1 .. v_oid_lst.count loop
      --
業務處理邏輯
      v_oid_lst(i).object_id := v_oid_lst(i).object_id + 1;
    end loop;
    forall i in v_oid_lst.first .. v_oid_lst.last
      insert into ljz_test
        (num, col)
      values
        (v_oid_lst(i).object_id, v_oid_lst(i).object_name)
      returning num, col bulk collect into v_oid_lst1;
    dbms_output.put_line('v_oid_lst1.count=' || v_oid_lst1.count ||
                         ',
隱式游標rowcount:' || sql%rowcount);
    fetch v_cur_oid bulk collect
      into v_oid_lst limit 1000;
    commit;
  end loop;
  close v_cur_oid;
end;

批量update、delete、insert,異常捕獲:

 SQL Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

 

--表說明:ljz_all_objects數據來自:all_objectstest1有兩個字段:col字符型最大長度10num數值型。
declare
  type v_tp_rec is record(
    object_name varchar2(50),
    object_id   number);
  type v_tp_obj is table of v_tp_rec index by simple_integer;
  v_objs v_tp_obj;
  type v_cur_tp_obj is ref cursor;
  v_cur_obj v_cur_tp_obj;
  v_lmt_cnt simple_integer := 1000;
  v_rn      simple_integer := 10;
begin
  open v_cur_obj for 'select object_name,object_id from ljz_all_objects where rownum<=:1 order by decode(object_id,117,300)'
    using v_rn;
  fetch v_cur_obj bulk collect
    into v_objs limit v_lmt_cnt;
  while v_objs.count > 0 loop
    dbms_output.put_line('v_objs.first=' || v_objs.first);
    for i in v_objs.first .. v_objs.last loop
      v_objs(i).object_id := v_objs(i).object_id + 1;
    end loop;
    begin
      --
批量插入,test1col字段大小為10,這里有異常
      forall i in v_objs.first .. v_objs.last
        insert into test1
          (col, num)
        values
          (v_objs(i).object_name, v_objs(i).object_id);
    exception
      --
如果不對forall執行異常捕獲,數據執行過程中如果出錯,會全部回滾,
      --
如果捕獲異常,假如數據在執行第5條時出錯,則前4條數據執行成功,第5條及其后面所有數據都不再執行。
      when others then
        --sql%bulk_exceptions.count
記錄異常數量,如果沒有使用save exceptions,若有異常該值為1,如下輸出是1
        dbms_output.put_line('sql%bulk_exceptions.count:' ||
                             sql%bulk_exceptions.count);
    end;
    --
批量更新
    forall i in v_objs.first .. v_objs.last
      update test1
         set num = v_objs(i).object_id
       where col = v_objs(i).object_name;
    --
對於批量更新,除了sql%rowcount幾個隱式游標屬性外,另具有sql%bulk_rowcount屬性,用來記錄第N行更新影響行數。
    if sql%bulk_rowcount(2) > 0 then
      dbms_output.put_line('
第二行更新影響行數:' || sql%bulk_rowcount(2));
    end if;
    begin
      --
批量刪除,使用save exceptions,和之前異常捕獲區別:使用save exceptions異常后可繼續執行直至結束。
      --
新屬性:sql%bulk_exceptions.countsql%bulk_exceptions(i).error_indexsql%bulk_exceptions(i).error_code
      forall i in v_objs.first .. v_objs.last save exceptions
        delete from test1 where v_objs(i).object_id / 0 > 1;
    exception
      when others then
        for i in 1 .. sql%bulk_exceptions.count loop
          dbms_output.put_line('sql%bulk_exceptions(i).error_index:' || sql%bulk_exceptions(i)
                               .error_index);
          dbms_output.put_line('sqlerrm sql%bulk_exceptions(i).error_code:' ||
                               sqlerrm(sql%bulk_exceptions(i).error_code));
        end loop;
    end;
    fetch v_cur_obj bulk collect
      into v_objs limit v_lmt_cnt;
  end loop;
  close v_cur_obj;
end;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM