巨大なテーブル(> 50.000.000)の更新で驚くほど速く動作する次のPL/SQL BULK-COLLECTを一緒に試しました。唯一の問題は、残りの<テーブルあたり5000行の更新を実行しないことです。 5000はFETCH命令の所定の制限です。BULK COLLECTの奇妙な動作
DECLARE
-- source table cursor (only columns to be updated)
CURSOR base_table_cur IS
select a.rowid, TARGET_COLUMN from TARGET_TABLE a
where TARGET_COLUMN is null;
TYPE base_type IS
TABLE OF base_table_cur%rowtype INDEX BY PLS_INTEGER;
base_tab base_type;
-- new data
CURSOR new_data_cur IS
select a.rowid,
coalesce(b.SOURCE_COLUMN, 'FILL_VALUE'||a.JOIN_COLUMN) TARGET_COLUMN from TARGET_TABLE a
left outer join SOURCE_TABLE b
on a.JOIN_COLUMN=b.JOIN_COLUMN
where a.TARGET_COLUMN is null;
TYPE new_data_type IS TABLE OF new_data_cur%rowtype INDEX BY PLS_INTEGER;
new_data_tab new_data_type;
TYPE row_id_type IS TABLE OF ROWID INDEX BY PLS_INTEGER;
row_id_tab row_id_type;
TYPE rt_update_cols IS RECORD (
TARGET_COLUMN TARGET_TABLE.TARGET_COLUMN%TYPE
);
TYPE update_cols_type IS
TABLE OF rt_update_cols INDEX BY PLS_INTEGER;
update_cols_tab update_cols_type;
dml_errors EXCEPTION;
PRAGMA exception_init (dml_errors,-24381);
BEGIN
OPEN base_table_cur;
OPEN new_data_cur;
LOOP
FETCH base_table_cur BULK COLLECT INTO base_tab LIMIT 5000;
IF base_table_cur%notfound THEN
DBMS_OUTPUT.PUT_LINE('Nothing to update. Exiting.');
EXIT;
END IF;
FETCH new_data_cur BULK COLLECT INTO new_data_tab LIMIT 5000;
FOR i IN base_tab.first..base_tab.last LOOP
row_id_tab(i) := new_data_tab(i).rowid;
update_cols_tab(i).TARGET_COLUMN := new_data_tab(i).TARGET_COLUMN;
END LOOP;
FORALL i IN base_tab.first..base_tab.last SAVE EXCEPTIONS
UPDATE (SELECT TARGET_COLUMN FROM TARGET_TABLE)
SET row = update_cols_tab(i)
WHERE ROWID = row_id_tab(i);
COMMIT;
EXIT WHEN base_tab.count < 5000; -- changing to 1 didn't help!
END LOOP;
COMMIT;
CLOSE base_table_cur;
CLOSE new_data_cur;
EXCEPTION
WHEN dml_errors THEN
FOR i IN 1..SQL%bulk_exceptions.count LOOP
dbms_output.put_line('Some error occured');
END LOOP;
END;
ここで私の間違いはありますか?それは私には正しいように見えます。
問題には関係ありませんが、ループの内側にコミットするのは悪い考えです。問題がある場合は、開始するために再起動するのがずっと難しくなります。 –
私が理解する限り、それはパフォーマンスがどこから来るのか正確です。 – royskatt
番号[トランザクションの最後にコミット](https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:74669804982988)。そして、なぜ[頻繁なコミットが悪い]という理由でTomから(https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:4951966319022)。バルク・コレクトの使用「PL/SQLとSQL間の通信のパフォーマンス・オーバーヘッドを最小限に抑える」(https://docs.oracle.com/database/122/LNPLS/plsql-optimization-and-tuning.htm#GUID-61D1B533) -DBB9-4150-91F9-0A4C9428391E)。 –