Oracle大量數據更新策略

生產上要修改某個產品的產品代號, 而咱們系統是以產品爲中心的, 牽一髮而動全身, 涉及表幾乎覆蓋所有, 有些表數據量是至關大的, 達到千萬, 億級別.sql

單純的維護產品代號的 SQL 是不難的, 可是性能是最大的問題, 最後採用了 rowid+forall分批更新策略.oop

 

細節涉及: 性能

遊標(rowidfetch

dbms_sql.Urowid_Table 優化

(異常聲明;) spa

fetch v_rowid_cursor bulk collect into v_rowid_table limit v_once_commit; ....net

forall i in 1 .. v_rowid_table.count save exceptions ...日誌

 

完整代碼:code

PL/SQL存儲過程分批更新↓blog

 1 --rowid+forall批量更新
 2 declare
 3   v_total_count integer default 500000; --待更新目標記錄總計
 4   v_once_commit integer default 10000; --單次提交量
 5   v_pre_prod_code char(8) := '90310004';
 6   v_new_prod_code char(8) := '9031000X';
 7   v_dml_name varchar2(100) := 'update tb_cust_vol_list 20181215 01';
 8   v_suc_count integer := 0; --成功提交計數
 9   v_err_count integer := 0; --失敗記錄數
10   v_curr_batch integer := 0; --當前提交批次
11   v_start_time date := sysdate; --開始時間
12   --待更新目標記錄rowids
13   cursor v_rowid_cursor is
14     select rowid from tb_cust_vol_list 
15      where prod_code = v_pre_prod_code
16      order by rowid; --rowid排序,提升效率
17   v_rowid_table dbms_sql.Uv_rowid_table; --臨時單次rowid放置表
18   v_error exception; --異常聲明
19   pragma exception_init(v_error, -24381); --指定ora-錯誤碼
20   
21 begin
22   --操做日誌
23   insert into tb_dml_log values (
24     v_dml_name,
25     v_total_count,
26     v_once_commit,
27     v_start_time,
28     v_start_time,
29     0, 0, 0, 0, 0
30   );
31   commit;
32   
33   open v_rowid_cursor; --打開rowids遊標
34   loop 
35     exit when v_rowid_cursor%notfound;
36     --臨時rowids表
37     fetch v_rowid_cursor bulk collect into v_rowid_table limit v_once_commit;
38     exit when v_rowid_table.count = 0;
39     
40     begin 
41       forall i in 1 .. v_rowid_table.count save exceptions
42         --rowid定位行更新
43         update tb_cust_vol_list set prod_code=v_new_prod_code where rowid=v_rowid_table(i); 
44     exception 
45       when v_error then --目標異常
46         dbms_output.put_line('ora-24381, error in array DML !');
47         dbms_output.put_line('exception count: ' || sql%bulk_exceptions.count);
48         v_err_count := v_err_count + sql%bulk_exceptions.count;
49       when others then 
50         dbms_output.put_line('ora-XXX error occurred !');
51         dbms_output.put_line('exception count: ' || sql%bulk_exceptions.count);
52         v_err_count := v_err_count + sql%bulk_exceptions.count;
53     end;
54     
55     v_suc_count := v_suc_count + v_rowid_table.count;
56     v_curr_batch := v_curr_batch + 1;
57     --更新log
58     update tb_dml_log a set 
59         a.curr_time=sysdate, 
60         a.curr_cost=ceil((sysdate-v_start_time)*24*60*60),
61         a.curr_batch=v_curr_batch,
62         a.process=v_suc_count/a.total_count,
63         a.suc_count=v_suc_count,
64         a.err_count=v_err_count 
65       where a.dml_name=v_dml_name;
66     commit;
67     
68   end loop;
69   
70   dbms_output.put_line('total error count: ' || v_err_count);
71 end;

 

有幫助的博客:
https://blog.csdn.net/leinuo180/article/details/23344647

 

其餘考慮:

若是有的表目標數據實在太大, 就算上述優化依然很費時間, 可將此表的目標數據拆分, 好比按月, 按編號.. 分幾個腳本, 維護時並行執行.

查詢語句獲取全部目標數據的 rowid 時, 若是佔比很大(索引空間大), 能夠嘗試禁用索引查詢, 使用全表並行查(網上看到的,本人還何嘗試).

超大表要注意索引空間的維護.

 

@20190126更新

批量數據更新方式

1)表重建

即先新建複製表(create 新表(...) as select ... from 舊錶 where ...),而後刪除舊錶(drop),最後修改表名(rename 新表名 to 舊錶名),最後恢復表結構(約束,索引等)。

2)rowid+forall PL/SQL存儲過程更新

即上面的辦法

3)JDBC程序分批更新

優勢是DB無關性,性能也不慢,只是數據量太大(千萬級)時,力不從心。

相關文章
相關標籤/搜索