【Oracle】LogMiner完全ガイド|DBMS_LOGMNR で REDO ログを解析して変更履歴を調査する方法まで解説

「昨日の何時に誰がこのデータを変更したのか調べたい」「意図せず削除されたレコードをどう特定するか」という場面で活躍するのがLogMiner(DBMS_LOGMNR)です。

LogMiner は Oracle の REDO ログ・アーカイブログを解析して、テーブルへの DML(INSERT・UPDATE・DELETE)の変更履歴を SQL 形式で取得します。監査・障害調査・誤操作の復旧に役立ちます。

この記事でわかること

  • LogMiner の仕組みと必要な権限・設定
  • DBMS_LOGMNR.ADD_LOGFILE でログファイルを追加する方法
  • DBMS_LOGMNR.START_LOGMNR で解析を開始するオプション
  • V$LOGMNR_CONTENTS で変更履歴を照会する方法
  • サプリメンタルロギングを有効にして LogMiner の精度を高める方法
  • LogMiner で取得できる UNDO SQL を使ったデータ復旧の考え方
スポンサーリンク

必要な権限と事前設定

LogMiner の実行に必要な権限を確認する
-- LogMiner を実行するユーザーに必要な権限
-- ① EXECUTE ON DBMS_LOGMNR(ログ解析の実行)
-- ② EXECUTE ON DBMS_LOGMNR_D(データディクショナリ操作)
-- ③ SELECT ANY TRANSACTION(全トランザクションへのアクセス)
-- ④ LOGMINING(Oracle 12c 以降、推奨)

-- SYS または DBA が権限を付与する
GRANT LOGMINING TO logminer_user;
GRANT EXECUTE ON DBMS_LOGMNR TO logminer_user;
GRANT EXECUTE ON DBMS_LOGMNR_D TO logminer_user;
GRANT SELECT ANY TRANSACTION TO logminer_user;

-- アーカイブモードが有効かどうかを確認する(LogMiner には推奨)
ARCHIVE LOG LIST;
-- ARCHIVELOG モードが望ましい(NOARCHIVELOG ではオンラインREDOログのみ解析可能)

-- サプリメンタルロギングの状態を確認する
SELECT log_mode, supplemental_log_data_min
FROM V$DATABASE;
-- SUPPLEMENTAL_LOG_DATA_MIN = YES → 最小サプリメンタルロギングが有効

サプリメンタルロギングを有効にする

通常の REDO ログは変更後の値のみを記録します。サプリメンタルロギングを有効にすると、変更前の値(BEFORE IMAGE)も記録されるようになり、LogMiner で UNDO SQL(変更前に戻す SQL)を取得できるようになります。

サプリメンタルロギングを有効にする
-- データベース全体の最小サプリメンタルロギングを有効にする
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
-- これで LogMiner で ROW_ID が取得可能になる

-- すべての列の変更前値を記録する(完全サプリメンタルロギング)
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA ALL COLUMNS;

-- 特定のテーブルのみ有効にする(推奨: 対象を絞る)
ALTER TABLE hr.employees ADD SUPPLEMENTAL LOG DATA ALL COLUMNS;

-- テーブルのサプリメンタルロギング設定を確認する
SELECT table_name,
       log_group_name,
       log_group_conditional,
       always
FROM DBA_LOG_GROUP_COLUMNS
WHERE owner = 'HR'
ORDER BY table_name;

-- データベースレベルの設定を確認する
SELECT name, value FROM V$PARAMETER WHERE name LIKE 'enable_goldengate%';

LogMiner の基本的な使い方

STEP1: ログファイルを追加する(ADD_LOGFILE)
-- オンライン REDO ログのパスを確認する
SELECT member FROM V$LOGFILE ORDER BY group#;

-- アーカイブログのパスを確認する(期間指定)
SELECT name, first_time, next_time
FROM V$ARCHIVED_LOG
WHERE first_time >= TRUNC(SYSDATE) - 1   -- 昨日以降
  AND standby_dest = 'NO'
ORDER BY sequence#;

-- LogMiner にログファイルを追加する
BEGIN
    -- 最初のファイル: DBMS_LOGMNR.NEW で新規セッションとして追加
    DBMS_LOGMNR.ADD_LOGFILE(
        logfilename => '/u01/app/oracle/archivelog/arch_001.arc',
        options     => DBMS_LOGMNR.NEW
    );

    -- 追加ファイル: ADDFILE で続けて追加
    DBMS_LOGMNR.ADD_LOGFILE(
        logfilename => '/u01/app/oracle/archivelog/arch_002.arc',
        options     => DBMS_LOGMNR.ADDFILE
    );
END;
/
STEP2: LogMiner セッションを開始する(START_LOGMNR)
-- LogMiner セッションを開始する
BEGIN
    DBMS_LOGMNR.START_LOGMNR(
        -- 解析時間範囲を指定する方法(ADD_LOGFILE でファイルを追加している場合)
        starttime   => SYSTIMESTAMP - INTERVAL '1' DAY,   -- 1日前から
        endtime     => SYSTIMESTAMP,                         -- 現在まで
        options     =>
            DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG           -- データディクショナリの取得方法
            + DBMS_LOGMNR.COMMITTED_DATA_ONLY              -- コミット済みデータのみ
            + DBMS_LOGMNR.SKIP_CORRUPTION                  -- 破損ブロックをスキップ
    );
END;
/

-- オプションの説明:
-- DICT_FROM_ONLINE_CATALOG : オンラインカタログを使用(現在の定義で解析)
-- DICT_FROM_REDO_LOGS      : ログ内のデータディクショナリを使用(過去の定義で解析)
-- COMMITTED_DATA_ONLY      : コミット済みトランザクションのみ返す
-- NO_ROWID_IN_STMT         : SQL 文に ROWID を含めない
-- DDL_DICT_TRACKING        : DDL 変更もトラッキングする
STEP3: V$LOGMNR_CONTENTS で変更履歴を照会する
-- 特定テーブルへの DML 変更履歴を確認する
SELECT
    timestamp,           -- 変更のタイムスタンプ
    seg_owner,           -- テーブル所有者
    seg_name,            -- テーブル名
    operation,           -- INSERT / UPDATE / DELETE / DDL
    username,            -- 実行ユーザー
    os_username,         -- OS ユーザー名
    sql_redo,            -- 変更を再現する SQL(REDO)
    sql_undo,            -- 変更を取り消す SQL(UNDO)
    row_id               -- 対象行の ROWID
FROM V$LOGMNR_CONTENTS
WHERE seg_name = 'EMPLOYEES'
  AND seg_owner = 'HR'
  AND operation IN ('INSERT', 'UPDATE', 'DELETE')
ORDER BY timestamp;

-- 特定ユーザーの操作を抽出する
SELECT timestamp, operation, seg_name, sql_redo
FROM V$LOGMNR_CONTENTS
WHERE username = 'APP_USER'
  AND operation != 'SELECT_FOR_UPDATE'
  AND seg_owner NOT IN ('SYS', 'SYSTEM')
ORDER BY timestamp;
STEP4: LogMiner セッションを終了する
-- LogMiner セッションを終了する(SGA リソースを解放)
BEGIN
    DBMS_LOGMNR.END_LOGMNR;
END;
/

UNDO SQL を使ったデータ復旧の考え方

削除されたレコードを UNDO SQL で復旧する(概念)
-- 誤って削除されたレコードの INSERT SQL を LogMiner から取得する例
SELECT sql_undo
FROM V$LOGMNR_CONTENTS
WHERE seg_name   = 'EMPLOYEES'
  AND seg_owner  = 'HR'
  AND operation  = 'DELETE'
  AND timestamp >= SYSTIMESTAMP - INTERVAL '1' HOUR
ORDER BY timestamp;
-- sql_undo 列には "INSERT INTO HR.EMPLOYEES (col1, col2, ...) VALUES (...)" が含まれる
-- この SQL を実行することで削除前の状態に戻せる

-- 注意: UNDO SQL の実行前に必ずデータの整合性を確認すること
-- ・外部キー制約・順序・トリガーの影響を検討する
-- ・FLASHBACK 機能で対応できる場合は Flashback を優先する
LogMiner vs Flashback
・最近の変更を取り消すなら Flashback(AS OF TIMESTAMP / Flashback Table)が簡単
・アーカイブログの長期間の変更履歴を調査するなら LogMiner
・LogMiner は UNDO SQL を提供するだけで、自動的に変更を元に戻すわけではない

まとめ

  • ADD_LOGFILE → START_LOGMNR → V$LOGMNR_CONTENTS 照会 → END_LOGMNR が基本フロー
  • COMMITTED_DATA_ONLY:コミット済みデータのみを返すオプション。通常はこれを指定する
  • サプリメンタルロギング:`ALTER DATABASE ADD SUPPLEMENTAL LOG DATA` で有効化。UNDO SQL の精度が向上する
  • sql_undo 列:変更を取り消す SQL が格納される。誤 DML の復旧に参照できる
  • Flashback との使い分け:最近の変更は Flashback、長期間・詳細な調査は LogMiner を使う

Flashback を使ったデータ復旧は Flashback完全ガイドを参照してください。REDO ログの構造と管理は オンライン REDO ログ完全ガイドも参照してください。