「昨日まで正しかったデータがいつ・誰によって変更されたのか」を調査したい場合、Oracle の Flashback Version Query が使えます。VERSIONS BETWEEN 句を使うと、特定の行(または条件に一致する行)が過去のどの時点でどのように変更されたかをSQL で一覧できます。
さらに Flashback Transaction Query(FLASHBACK_TRANSACTION_QUERY ビュー)と組み合わせると、特定のトランザクション(XID)の内容や UNDO SQL を確認できます。
この記事でわかること
- Flashback Version Query(VERSIONS BETWEEN)で行の変更履歴を一覧する方法
- VERSIONS_XID・VERSIONS_OPERATION・VERSIONS_STARTSCN などの擬似列の意味
- SCN ベースと TIMESTAMP ベースの指定方法の違い
- Flashback Transaction Query で XID からトランザクション詳細を確認する方法
- UNDO_RETENTION と Flashback で参照できる履歴の期間
- AS OF TIMESTAMP・Flashback Table との使い分け
Flashback Version Query: VERSIONS BETWEEN の基本構文
VERSIONS BETWEEN を SELECT 文の FROM 句に付けることで、UNDO に残っている過去の各バージョン(コミット済みの変更点)を行として取得できます。
VERSIONS BETWEEN の基本的な使い方
-- VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE: 取得可能な全期間の変更履歴を返す
SELECT
VERSIONS_XID AS xid, -- トランザクション ID
VERSIONS_OPERATION AS operation, -- I=INSERT, U=UPDATE, D=DELETE
VERSIONS_STARTSCN AS start_scn, -- この版の開始 SCN
VERSIONS_ENDSCN AS end_scn, -- この版の終了 SCN(NULL=現在の版)
VERSIONS_STARTTIME AS start_time, -- この版の開始日時(近似)
VERSIONS_ENDTIME AS end_time, -- この版の終了日時
employee_id, last_name, salary -- テーブルの実データ
FROM employees VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE
WHERE employee_id = 107
ORDER BY VERSIONS_STARTSCN NULLS FIRST;
-- VERSIONS_OPERATION の値:
-- I: この版は INSERT によって作られた(行が新規追加された)
-- U: この版は UPDATE によって作られた(行が変更された)
-- D: この版は DELETE によって作られた(行が削除された)
-- NULL: 現在の版(最新データ)
-- TIMESTAMP ベースで過去2時間の変更履歴を取得する
SELECT
VERSIONS_STARTTIME, VERSIONS_OPERATION, employee_id, last_name, salary
FROM employees VERSIONS BETWEEN TIMESTAMP
(SYSTIMESTAMP - INTERVAL '2' HOUR)
AND
SYSTIMESTAMP
WHERE employee_id = 107
ORDER BY VERSIONS_STARTTIME;
-- SCN ベースで特定の SCN 範囲を指定する
SELECT
VERSIONS_STARTSCN, VERSIONS_OPERATION, employee_id, salary
FROM employees VERSIONS BETWEEN SCN 5000000 AND 5100000
WHERE department_id = 60
ORDER BY VERSIONS_STARTSCN;
VERSIONS BETWEEN の動作の注意点
- VERSIONS BETWEEN はコミット済みの変更だけを返す。ロールバックされたトランザクションは含まれない
- 取得できる期間は UNDO_RETENTION の設定に依存する。UNDO が上書きされると古い版は取得不可になる
- VERSIONS_STARTSCN が NULL の行は INSERT 前(行が存在しなかった期間)を示す場合がある
- DDL(TRUNCATE・ALTER TABLE)が発生した場合は以前の版は取得できない
Flashback Version Query の擬似列一覧
| 擬似列 | 型 | 説明 |
|---|---|---|
VERSIONS_XID |
RAW(8) | 変更を行ったトランザクション ID(XID)。FLASHBACK_TRANSACTION_QUERY の XID と一致する |
VERSIONS_OPERATION |
VARCHAR2(1) | 変更の種類:I(INSERT) / U(UPDATE) / D(DELETE)。現在の版は NULL |
VERSIONS_STARTSCN |
NUMBER | この版が開始した SCN。最初の版は NULL |
VERSIONS_ENDSCN |
NUMBER | この版が終了した SCN。現在の版(最新)は NULL |
VERSIONS_STARTTIME |
VARCHAR2 | この版が開始したおよその日時(SCN から変換した近似値) |
VERSIONS_ENDTIME |
VARCHAR2 | この版が終了したおよその日時。現在の版は NULL |
VERSIONS_ROW_FILTER |
– | 行フィルタリングに使用する内部列(通常は使わない) |
Flashback Transaction Query: XID からトランザクション詳細を確認する
Flashback Version Query で取得した VERSIONS_XID を使って、FLASHBACK_TRANSACTION_QUERY ビューからそのトランザクションが行ったすべての変更と UNDO SQL を取得できます。
Flashback Transaction Query で変更内容と UNDO SQL を確認する
-- FLASHBACK_TRANSACTION_QUERY の権限: SELECT ANY TRANSACTION または FLASHBACK ANY TABLE が必要
-- XID を指定してそのトランザクションの詳細を確認する
SELECT
xid,
operation, -- INSERT / UPDATE / DELETE / UNKNOWN
start_timestamp, -- トランザクション開始日時
commit_timestamp, -- COMMIT 日時
logon_user, -- 変更を行ったユーザー
undo_sql, -- 変更を元に戻すための SQL(UNDO SQL)
table_name,
table_owner
FROM FLASHBACK_TRANSACTION_QUERY
WHERE xid = HEXTORAW('01000A0058060000') -- VERSIONS_XID の値
ORDER BY undo_change#;
-- VERSIONS BETWEEN と FLASHBACK_TRANSACTION_QUERY を結合して確認する
SELECT
v.VERSIONS_STARTTIME,
v.VERSIONS_OPERATION,
v.employee_id,
v.last_name,
v.salary,
f.logon_user, -- 変更を行ったユーザー
f.undo_sql -- 変更を元に戻す SQL
FROM employees VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE v
JOIN FLASHBACK_TRANSACTION_QUERY f ON v.VERSIONS_XID = f.xid
WHERE v.employee_id = 107
AND v.VERSIONS_OPERATION IS NOT NULL -- 現在の版を除く
ORDER BY v.VERSIONS_STARTSCN;
-- UNDO SQL を使って特定の変更を手動で元に戻す例
-- undo_sql: 'UPDATE "HR"."EMPLOYEES" SET SALARY=5000 WHERE ROWID=''AAABkUAAEAAAAC7AAA'';'
-- → undo_sql を実行すれば変更前の状態に戻せる
Flashback Version Query と AS OF TIMESTAMP の使い分け
| 機能 | 目的 | 取得対象 | 主な用途 |
|---|---|---|---|
| AS OF TIMESTAMP | 過去の特定時点のスナップショット | その時点での行の値(1行1版) | 「昨日の午前9時のデータを見たい」 |
| VERSIONS BETWEEN | 行の変更履歴の一覧 | 期間内のすべての版(複数行) | 「この行は誰が・いつ・何回変更したか」 |
| Flashback Table | テーブルを過去の状態に戻す(DML) | テーブル全体を過去に戻す | 「誤って DELETE したテーブルを元に戻したい」 |
| Flashback Transaction Query | 特定トランザクションの詳細と UNDO SQL | トランザクションが変更した全行と操作 | 「このトランザクションが何を変更したか・元に戻したい」 |
UNDO_RETENTION と取得できる履歴の期間
UNDO_RETENTION と参照可能期間の確認
-- 現在の UNDO_RETENTION を確認する(秒単位) SHOW PARAMETER undo_retention; -- undo_retention = 900 (デフォルト): 最低 900秒(15分)UNDO を保持する保証 -- より長い履歴を参照するには UNDO_RETENTION を増やす ALTER SYSTEM SET UNDO_RETENTION = 86400; -- 24時間(86400秒)保持 -- undo_retention はガイドラインであり、UNDO 表領域が満杯の場合は -- 古い UNDO から上書きされる(GUARANTEE なし) -- UNDO 表領域に RETENTION GUARANTEE を設定すると期限前上書きを防止できる ALTER TABLESPACE undotbs1 RETENTION GUARANTEE; -- 現在参照可能な SCN の範囲を確認する SELECT oldest_flashback_scn, oldest_flashback_time FROM V$FLASHBACK_DATABASE_LOG; -- oldest_flashback_scn より前の SCN は参照できない(UNDO が消えている可能性) -- ORA-01555 (snapshot too old) が出たら UNDO が不足している -- VERSIONS BETWEEN で ORA-01555 が出る場合は UNDO_RETENTION を増やすか -- UNDO 表領域を拡張する
まとめ
- Flashback Version Query:SELECT 文に VERSIONS BETWEEN SCN/TIMESTAMP を付けるだけで行の変更履歴を取得できる。コミット済みの変更がすべて列挙される
- 擬似列:VERSIONS_XID(トランザクション ID)・VERSIONS_OPERATION(I/U/D)・VERSIONS_STARTSCN / ENDSCN・VERSIONS_STARTTIME / ENDTIME が取得できる
- Flashback Transaction Query:FLASHBACK_TRANSACTION_QUERY ビューで XID から「誰が・いつ・何を変更したか」と UNDO SQL を確認できる。SELECT ANY TRANSACTION 権限が必要
- UNDO_RETENTION:参照できる履歴の期間を制御する。デフォルト 900 秒を超えると UNDO が上書きされる可能性がある
- AS OF TIMESTAMP との違い:AS OF は特定時点の単一スナップショット、VERSIONS BETWEEN は期間内の全変更履歴を返す
行レベルの変更を長期保存する場合は Flashback Data Archive(Total Recall)も有効です。Flashback Data Archive 完全ガイドを参照してください。Flashback Table でテーブル全体を過去の状態に戻す方法は Flashback 完全ガイドも参照してください。