誤解していると思います-セーブポイントにロールバックすると、Oracleはセーブポイントの後に行われたすべての作業を元に戻す必要があります(セーブポイントの前に行われたコミットされていない作業は引き続き保持されます)。
一時テーブルの場合、Oracle はストレージ (セッションの一時セグメント) を遅延して割り当てます (セッションの一時セグメント)。通常のテーブルを TRUNCATE した場合のように、行を個別に削除するのではなく、単にストレージの割り当てを解除できます。
データが入力される前にセーブポイントがあり、そのセーブポイントにロールバックした場合にどうなるかを知りたいと思っていました.Oracleはストレージの割り当てを解除しますか、それともストレージを保持してその中の行を削除しますか?
前者であることが判明しました-切り捨てのように動作します。
SAVEPOINT f0;
SELECT * FROM v$tempseg_usage; -- Should show nothing for your session
insert into table_1 values('one');
insert into table_1 values('two');
SELECT * FROM v$tempseg_usage; -- Should show a DATA row for your session
savepoint f1;
insert into table_1 values('three');
insert into table_1 values('four');
rollback to f1; -- Undo three and four but preserve one and two
SELECT * FROM v$tempseg_usage; -- Still shows a DATA row for your session
rollback to f0; -- Undo all the inserts
SELECT * FROM v$tempseg_usage; -- row for your session has gone
これが重要な理由は、切り捨てではなく通常の削除を行う場合でも、テーブルのフル スキャンではすべてのデータ ブロックをふるいにかけ、データが含まれているかどうかを確認する必要があるためです。空のテーブルに対する DML は、以前にテーブルに大量のデータがあった場合、大量の I/O が発生する可能性があります。
私はまさにそれを行っているいくつかのコードを高速化しようとしています - それは永続的なテーブルに参加し、結果を呼び出し元に返すことができるように、一部のものをスクラッチパッドとして一時テーブルに押し込んでいます。一時テーブルはこのルーチンの利益のためだけにあるため、ルーチンの最後に削除しても安全ですが、親トランザクション内で何度も呼び出される可能性があるため、切り捨てることはできません (TRUNCATE
は DDL であり、コミットしますまたは、同じトランザクション内の呼び出しが別の行を取得します。DELETE による消去は、特にテーブルにインデックスがなく、テーブルに対する選択が常にフル スキャンになるため、かなりのオーバーヘッドを引き起こします。
私が検討しているオプションはSAVEPOINT
、ルーチンの開始時に を使用し、一時的な作業を行ってから、結果が返される直前にセーブポイントにロールバックすることです。別のオプションとして、ルーチンを自律型トランザクション内に配置することもできますが、それは C コードを PL/SQL ストアド プロシージャに移植することを意味し、呼び出し元によって挿入されたコミットされていないデータに一時テーブルを結合する必要がある場合は、とにかく機能しません。
私は12cで調査を行ったことに注意してください-このリリースでは一時テーブルにいくつかの改善がありました(https://oracle-base.com/articles/misc/temporary-tablesを参照)が、動作に影響はないと思いますwrt セーブポイント。