我有一個非常大的表格(5毫米記錄)。我試圖使用隨機字母數字爲表中的每個記錄混淆表的VARCHAR2列。我的過程在較小的數據集上成功執行,但最終將在遠程數據庫上使用,該數據庫的設置無法控制,所以我想批量執行UPDATE語句以避免耗盡undospace。如何批量更新Oracle pl/sql中的大表以避免耗盡undospace?
是否有某種選項可以啓用,或者以標準方式進行區塊更新?
我會補充說,不會有沒有被混淆的記錄的任何顯着特徵,所以我想在循環中使用rownum不會有效(我認爲)。
我有一個非常大的表格(5毫米記錄)。我試圖使用隨機字母數字爲表中的每個記錄混淆表的VARCHAR2列。我的過程在較小的數據集上成功執行,但最終將在遠程數據庫上使用,該數據庫的設置無法控制,所以我想批量執行UPDATE語句以避免耗盡undospace。如何批量更新Oracle pl/sql中的大表以避免耗盡undospace?
是否有某種選項可以啓用,或者以標準方式進行區塊更新?
我會補充說,不會有沒有被混淆的記錄的任何顯着特徵,所以我想在循環中使用rownum不會有效(我認爲)。
如果要更新表中的每一行,最好使用創建表作爲選擇,然後刪除/截斷原始表並使用新數據重新附加。如果你有分區選項,你可以用一個分區創建你的新表格作爲表格,只需將它與EXCHANGE PARTITION交換即可。
插入操作需要很少的撤消操作,直接路徑插入與nologging(/ + APPEND /提示)也不會產生太多的重做。
無論使用哪種機制,都有可能成爲舊值的'取證'證據(例如,由於行移動而在撤消或保留在「可用」空間中)。
我通過將主鍵映射到整數(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
你可能有更多的分區,並可能希望把這個變成一個循環(有一些提交)。
如果需要事件大小的集合,應該使用NTILE()分析函數; ORA_HASH可能具有不可預知的值,特別是當使用一個值不是2的冪數來存儲桶的數量時。 ORA_HASH(n,3)可以有4個值,所以你的例子會錯過更新大約1/4的數據。 – 2010-08-23 14:50:58
Adam:請注意我使用了「MOD(ORA_HASH(ID),3)」,而不是「ORA_HASH(ID,3)」。我故意使用MOD,因爲ORA_HASH的額外參數令人困惑。 感謝NTILE()參考。我仍然不完全熟悉分析。 – 2010-08-23 16:10:19
@ adam-musch:試圖在WHERE中使用NTILE會給我錯誤:'ORA-30483:窗口函數在這裏是不允許的' – Greg 2013-07-30 16:56:37
以下是未經測試,但應該工作:
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。
如果我不得不更新數百萬條記錄,我可能會選擇不更新。
我更可能創建臨時表,然後從舊錶插入數據,因爲插入犯規佔用了大量的空間,重做和花費較少的撤消。
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 - 在短的時間內,將採取更新 數據。
似乎是[AskTom]上的相同答案(https://asktom.oracle.com/pls/asktom/f?p=100:11:0::NO::P11_QUESTION_ID:6407993912330) – 0909EM 2015-09-18 13:28:47
不要忘記禁用引用表的外鍵約束。 – Codo 2010-08-23 21:04:04