2010-08-22 51 views
3

我有一個非常大的表格(5毫米記錄)。我試圖使用隨機字母數字爲表中的每個記錄混淆表的VARCHAR2列。我的過程在較小的數據集上成功執行,但最終將在遠程數據庫上使用,該數據庫的設置無法控制,所以我想批量執行UPDATE語句以避免耗盡undospace。如何批量更新Oracle pl/sql中的大表以避免耗盡undospace?

是否有某種選項可以啓用,或者以標準方式進行區塊更新?

我會補充說,不會有沒有被混淆的記錄的任何顯着特徵,所以我想在循環中使用rownum不會有效(我認爲)。

回答

5

如果要更新表中的每一行,最好使用創建表作爲選擇,然後刪除/截斷原始表並使用新數據重新附加。如果你有分區選項,你可以用一個分區創建你的新表格作爲表格,只需將它與EXCHANGE PARTITION交換即可。

插入操作需要很少的撤消操作,直接路徑插入與nologging(/ + APPEND /提示)也不會產生太多的重做。

無論使用哪種機制,都有可能成爲舊值的'取證'證據(例如,由於行移動而在撤消或保留在「可用」空間中)。

+0

不要忘記禁用引用表的外鍵約束。 – Codo 2010-08-23 21:04:04

0

我通過將主鍵映射到整數(mod n),然後對每個x執行更新,其中0 < = x < n。

例如,也許你是不幸的,主鍵是一個字符串。您可以與您喜愛的散列函數散列,然後將其分解成三個分區:

UPDATE myTable SET a=doMyUpdate(a) WHERE MOD(ORA_HASH(ID), 3)=0 
UPDATE myTable SET a=doMyUpdate(a) WHERE MOD(ORA_HASH(ID), 3)=1 
UPDATE myTable SET a=doMyUpdate(a) WHERE MOD(ORA_HASH(ID), 3)=2 

你可能有更多的分區,並可能希望把這個變成一個循環(有一些提交)。

+2

如果需要事件大小的集合,應該使用NTILE()分析函數; ORA_HASH可能具有不可預知的值,特別是當使用一個值不是2的冪數來存儲桶的數量時。 ORA_HASH(n,3)可以有4個值,所以你的例子會錯過更新大約1/4的數據。 – 2010-08-23 14:50:58

+0

Adam:請注意我使用了「MOD(ORA_HASH(ID),3)」,而不是「ORA_HASH(ID,3)」。我故意使用MOD,因爲ORA_HASH的額外參數令人困惑。 感謝NTILE()參考。我仍然不完全熟悉分析。 – 2010-08-23 16:10:19

+0

@ adam-musch:試圖在WHERE中使用NTILE會給我錯誤:'ORA-30483:窗口函數在這裏是不允許的' – Greg 2013-07-30 16:56:37

2

以下是未經測試,但應該工作:

declare 
    l_fetchsize number := 10000; 
    cursor cur_getrows is 
    select rowid, random_function(my_column) 
    from my_table; 

    type rowid_tbl_type  is table of urowid; 
    type my_column_tbl_type is table of my_table.my_column%type; 

    rowid_tbl  rowid_tbl_type; 
    my_column_tbl my_column_tbl_type; 
begin 

    open cur_getrows; 
    loop 
    fetch cur_getrows bulk collect 
     into rowid_tbl, my_column_tbl 
     limit l_fetchsize; 
    exit when rowid_tbl.count = 0; 

    forall i in rowid_tbl.first..rowid_tbl.last 
     update my_table 
     set my_column = my_column_tbl(i) 
     where rowid  = rowid_tbl(i); 
    commit; 
    end loop; 
    close cur_getrows; 
end; 
/

這不是最佳的效率 - 一個單一的更新將是 - 但它會做的更小,用戶可調批次,使用ROWID。

0

如果我不得不更新數百萬條記錄,我可能會選擇不更新。

我更可能創建臨時表,然後從舊錶插入數據,因爲插入犯規佔用了大量的空間,重做和花費較少的撤消。

CREATE TABLE new_table as select <do the update "here"> from old_table; 

index new_table 
grant on new table 
add constraints on new_table 
etc on new_table 

drop table old_table 
rename new_table to old_table; 

你可以做,使用並行查詢,對大多數操作產生非常 小重做,並完全關閉撤銷NOLOGGING - 在短的時間內,將採取更新 數據。

+1

似乎是[AskTom]上的相同答案(https://asktom.oracle.com/pls/asktom/f?p=100:11:0::NO::P11_QUESTION_ID:6407993912330) – 0909EM 2015-09-18 13:28:47