特定の変更を「なかったこと」にする:Oracle フラッシュバック・トランザクション活用術

Oracle Master Gold

Oracle Databaseで誤った更新をコミットしてしまった際、テーブル全体を戻す「フラッシュバック表」では影響範囲が広すぎることがあります。「この特定の更新(トランザクション)だけをスマートに取り消したい」――そんな時に役立つのが フラッシュバック・トランザクション(FLASHBACK TRANSACTION) です。

本記事では、トランザクションID(XID)を特定し、依存関係を含めてデータを安全に復元する手順を解説します。

💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?

Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?


🔁 フラッシュバック・トランザクションとは?

特定のトランザクションを指定し、その変更内容を打ち消す「補正用SQL」を自動実行してデータを元に戻す機能です。

  • ピンポイント復元:特定の UPDATEDELETE だけをターゲットにできます。
  • 依存関係の解消:その変更に依存して後から行われた別のトランザクションもまとめて取り消せます。

📌 実行のための前提条件

この機能を利用するには、事前に「サプリメンタル・ロギング(追加ログ)」が有効である必要があります。

項目内容
自動UNDO管理UNDO_MANAGEMENT = AUTO であること。
サプリメンタル・ログMIN(最小サプリメンタル・ロギング)が有効であること。
UNDO保持期間該当トランザクションのUNDO情報が上書きされずに残っていること。

📋 実践ステップ1:環境準備とサプリメンタル・ログの設定

まず、ログ設定を確認し、テスト用のデータを準備します。

最小サプリメンタル・ロギングの有効化

-- 現在の設定確認
SELECT supplemental_log_data_min FROM v$database;

-- 有効化(NOの場合のみ実行)
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;

-- 設定後の確認(YESになればOK)
SELECT supplemental_log_data_min FROM v$database;

-- ログ・スイッチの実行
ALTER SYSTEM SWITCH LOGFILE;

テストテーブルの作成とデータ投

CREATE TABLE emp_test (
  empno NUMBER PRIMARY KEY,
  ename VARCHAR2(20),
  sal NUMBER
);

INSERT INTO emp_test VALUES (1001, 'SCOTT', 3000);
INSERT INTO emp_test VALUES (1002, 'JONES', 2500);
COMMIT;

📋 実践ステップ2:誤操作の実行と特定

誤操作の実行

「SCOTTの給与を誤って0にしてしまった」という状況を再現します。

UPDATE emp_test SET sal = 0 WHERE empno = 1001;
COMMIT;

トランザクションID(XID)の特定

過去のトランザクション情報を管理している flashback_transaction_query ビューを検索します。

-- 表示設定
alter session set nls_date_format='YYYY/MM/DD HH24:MI:SS';
set linesize 1000
col operation for a10
col undo_sql for a80
col table_name for a10

-- 履歴の照会
SELECT xid, operation, undo_sql, table_name, start_timestamp
FROM flashback_transaction_query
WHERE table_name = 'EMP_TEST';

ここで表示される XID(例:0800130000040000)と、復元用の UNDO_SQL を確認します。


📋 実践ステップ3:トランザクションの取り消し実行

DBMS_FLASHBACK.TRANSACTION_BACKOUT プロシージャを使用して、特定の処理をロールバックします。

-- SYSDBA権限で実行
conn / as sysdba

BEGIN
  DBMS_FLASHBACK.TRANSACTION_BACKOUT(
    numtxns => 1,
    xids    => SYS.XID_ARRAY('0800130000040000'), -- 特定したXIDを指定
    options => DBMS_FLASHBACK.CASCADE            -- 依存関係もまとめて処理
  );
END;
/

-- 実行後の確認
SELECT * FROM test1.emp_test;
-- SALが3000に戻っていれば成功!
SQL> SELECT supplemental_log_data_min FROM v$database;

SUPPLEMENTAL_LOG_DATA_MI
------------------------
NO

SQL> ALTER DATABASE ADD SUPPLEMENTAL LOG DATA; ★最小サプリメンタルロギングを設定

データベースが変更されました。

SQL> SELECT supplemental_log_data_min FROM v$database;

SUPPLEMENTAL_LOG_DATA_MI
------------------------
YES

SQL> ALTER SYSTEM SWITCH LOGFILE;

システムが変更されました。

SQL> CREATE TABLE emp_test (
2 empno NUMBER PRIMARY KEY,
3 ename VARCHAR2(20),
4 sal NUMBER
5 );

表が作成されました。

SQL> INSERT INTO emp_test VALUES (1001, 'SCOTT', 3000);

1行が作成されました。

SQL> INSERT INTO emp_test VALUES (1002, 'JONES', 2500);

1行が作成されました。

SQL> SELECT * FROM emp_test;

EMPNO ENAME SAL
---------- ------------------------------ ----------
1001 SCOTT 3000
1002 JONES 2500

SQL> commit;

コミットが完了しました。

SQL> UPDATE emp_test SET sal = 0 WHERE empno = 1001; ★誤った処理を実行

1行が更新されました。

SQL> SELECT * FROM emp_test;

EMPNO ENAME SAL
---------- ------------------------------ ----------
1001 SCOTT 0
1002 JONES 2500

SQL> commit;

コミットが完了しました。

SQL> alter session set nls_date_format='YYYY/MM/DD HH24:MI:SS';

セッションが変更されました。

SQL> set linesize 1000
SQL> col operation for a10
SQL> col undo_sql for a80
SQL> col table_name for a10
SQL> SELECT xid, operation, undo_sql, table_name, start_timestamp
2 FROM flashback_transaction_query
3 WHERE table_name = 'EMP_TEST';

XID OPERATION UNDO_SQL TABLE_NAME START_TIMESTAMP
---------------- ---------- -------------------------------------------------------------------------------- ---------- -------------------
03001A00F7030000 INSERT delete from "TEST1"."EMP_TEST" where ROWID = 'AAASHRAAHAAAAF+AAB'; EMP_TEST 2025/03/23 11:24:50
03001A00F7030000 INSERT delete from "TEST1"."EMP_TEST" where ROWID = 'AAASHRAAHAAAAF+AAA'; EMP_TEST 2025/03/23 11:24:50
0800130000040000 UPDATE update "TEST1"."EMP_TEST" set "SAL" = '3000' where ROWID = 'AAASHRAAHAAAAF+AAA'; EMP_TEST 2025/03/23 11:25:26 ★この時点に戻す

SQL> conn / as sysdba
接続されました。
SQL> BEGIN
2 DBMS_FLASHBACK.TRANSACTION_BACKOUT(
3 numtxns => 1,
4 xids => SYS.XID_ARRAY('0800130000040000'), ★
5 options => DBMS_FLASHBACK.CASCADE
6 );
7 END;
8 /

PL/SQLプロシージャが正常に完了しました。

SQL> SELECT * FROM test1.emp_test;

EMPNO ENAME SAL
---------- ------------------------------ ----------
1001 SCOTT 3000 ★元の値に戻っている
1002 JONES 2500

オプション(options)の種類

オプション内容
NOCASCADE他に依存するトランザクションがない場合のみ実行。あればエラー。
CASCADE該当トランザクション以降に発生した「依存する変更」もすべて取り消す。(推奨)
NOCASCADE_FORCE依存関係を無視して該当SQLだけを強制実行する。

🧷 依存トランザクションとは?

下図のように、トランザクション1(T1)で変更したデータを、別のトランザクション2(T2)がさらに書き換えた場合、T2はT1に「依存」している状態になります。T1だけを消すと整合性が崩れるため、通常は CASCADE を使用してまとめて復元します。


FAQ

Q1:一般ユーザーでも実行できますか?

A1:実行には SELECT ANY TRANSACTION 権限や、DBMS_FLASHBACK パッケージの実行権限が必要です。基本的にはDBAロールを持つユーザーが作業します。

Q2:UNDO_SQLを自分でコピーして実行するのと何が違いますか?

A2:TRANSACTION_BACKOUT を使うと、Oracleが自動的に依存関係(Foreign Keyの制約や他の更新との競合)をチェックし、整合性を保ったまま戻してくれます。手動実行より安全です。

Q3:DDL(テーブル定義変更)も戻せますか?

A3:いいえ、DML(INSERT/UPDATE/DELETE)の取り消しに限定されます。


まとめ

  • フラッシュバック・トランザクションは、特定の変更をピンポイントで消去する。
  • XID(トランザクションID)を特定することが最初のステップ。
  • サプリメンタル・ロギングの有効化が必須の事前準備。
  • CASCADEオプションを活用し、依存関係による不整合を防ぐ。

※本記事の検証環境:Oracle Database 19c。商用環境で実行する際は、事前に十分なバックアップを取得することを強く推奨します。


おわりに

いかがでしたか?「データの全戻し」ではなく「特定のミスだけを消す」というアプローチができるようになると、リカバリの柔軟性が一気に高まります。いざという時のために、検証環境で一度このフローを試しておくことをおすすめします。

さらなる高度な復元手法として、複数のテーブルを跨ぐ同期が必要な場合は「フラッシュバック・データベース」についても併せて学ぶと良いでしょう。


[参考]
Oracle Flashback Technologyの使用

フラッシュバック・データベースの構築手順と運用の極意
Oracle Databaseを運用する上で、最も強力な「保険」の一つがフラッシュバック・データベース(Flashback Database)です。 ユーザーが誤って大規模な更新を行ったり、アプリケーションのバグでデータが壊れたりした際、デ…
Oracle フラッシュバックテクノロジーとは?
〜誤操作からの救世主、Oracleの強力な巻き戻し機能を解説〜Oracle Databaseには、時間を巻き戻す魔法のような機能「フラッシュバックテクノロジー(Flashback Technology)」が備わっています。ユーザーが誤ってデ…

💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?

Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?

コメント

タイトルとURLをコピーしました