如果你有性能問題遍歷每個記錄,但表對於單個更新而言太大,您可以考慮使用BULK INTO ... LIMIT和FORALL批量更新。
CREATE TABLE klm (abc INTEGER, xyz INTEGER);
CREATE TABLE update_data (abc INTEGER, cdf INTEGER);
-- Have pairs of numbers (1000 rows)
INSERT INTO klm SELECT rownum, rownum FROM dual CONNECT BY level <= 1000;
-- Update every second row with 9999
INSERT INTO update_data SELECT rownum * 2, 9999 FROM dual CONNECT BY level <= 500;
DECLARE
CURSOR c1
IS
-- Select the key to be updated and the new value
SELECT abc, cdf FROM update_data;
-- Table type and table variable to store rows fetched from the cursor
TYPE t_update IS TABLE OF c1%rowtype;
update_tab t_update;
BEGIN
OPEN c1;
LOOP
-- Fetch next 30 rows into update table
FETCH c1 BULK COLLECT INTO update_tab LIMIT 30;
-- Exit when there were no more rows fetched
EXIT WHEN update_tab.count = 0;
-- This is the key point; uses update_tab to bulk-bind UPDATE statement
-- and run it for 30 rows in a single context switch
FORALL i IN 1..update_tab.count
UPDATE klm
SET klm.xyz = update_tab(i).cdf
WHERE update_tab(i).abc = klm.abc;
COMMIT;
END LOOP;
CLOSE c1;
END;
/
這背後的基本原理是Oracle實際上有單獨的引擎運行SQL語句和PL/SQL程序。無論程序何時遇到SQL語句,都會將其交給SQL引擎執行。這被稱爲「上下文切換」,並且花費大量時間,尤其是在循環中完成時。
批量綁定旨在通過每[批量大小]記錄僅執行一次上下文切換來減少此開銷。同樣,這當然不像單個DML操作那樣有效,但對於大型表或複雜查詢,它可能是最好的可行解決方案。
我已經使用上面的方法來更新100M-500M記錄批量大小爲10K-100K的表,它工作正常。但是您需要在您的環境中嘗試批量大小以獲得最佳性能。
感謝您的回答。我嘗試了第二種方法,但得到了一個錯誤SQL錯誤:ORA-01779:無法修改映射到非鍵保存表的列 – era
而且我也無法理解第一個解決方案的哪裏存在部分。爲什麼你檢查t2.abc = t2.abc?謝謝 – era
關於第一個答案; update_data又是一個生成的數據。我不認爲這是執行update_data SELECT查詢兩次(在SET部分和WHERE EXIST中)的最佳選擇。謝謝 – era