Oracle DatabaseのREDOログとUNDOログの中身を見てみる

## はじめに
OracleデータベースのREDOログとUNDOログは、データベースのリカバリと整合性を維持するために重要な役割を果たします。
LogMinerを使用してREDOログとUNDOログ見てどのような内容か確認してみました。


**REDOログ**
REDOログは、RE(再)+DO(実行)で再実行用のログ。Oracleデータベースの変更操作を記録するログファイルで、データベースのクラッシュや障害が発生した場合に、データをリカバリするために使用される。

**UNDOログ**
UNDOログは、UN(しない)+DO(実行)で実行取り消し用のログ。トランザクションが行った変更を元に戻ので、トランザクションのロールバックやデータの一貫性を維持できる。

**LogMiner**
LogMinerは、LogMinerは、Oracleデータベースのツールの一つであり、REDOログファイルの内容を解析して、データベースに対する変更履歴を確認できる機能です。

## 解析準備
**1. LogMinerのセットアップ**

まず、Oracleデータベース内に新しいディレクトリオブジェクトを作成し、pudding_logmnr_dict.oraというLogMinerの辞書ファイルを作成します。LogMinerの辞書ファイルは、Oracleデータベースのメタデータ情報を含むファイルであり、REDOログファイルを解析する際に必要な情報が含まれます。なお、今回はプリン（英語ではpudding）を例に使用しています。「プリンは栄養たっぷりん。言うてな！」
```sql
CREATE OR REPLACE DIRECTORY logmnr_dir AS '/u01/app/oracle';
EXEC DBMS_LOGMNR_D.BUILD(dictionary_filename => 'pudding_logmnr_dict.ora', dictionary_location => 'LOGMNR_DIR');
```

**2. サンプルテーブルの作成**
次に、プリンに関連するサンプルテーブルを作成し、データを挿入します。
```sql
CREATE TABLE eiyou (
    id NUMBER PRIMARY KEY,
    name VARCHAR2(50)
);

INSERT INTO eiyou (id, name) VALUES (1, 'Purin');
INSERT INTO eiyou (id, name) VALUES (2, 'Pudding');
```
↓みたいな、ちょっとしたテーブルです。

![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/7cec36cb-0eb4-b560-b2fe-d89be13d0ad5.png)


**3. LogMinerに解析対象のREDOログファイルを追加**
DBMS_LOGMNR.ADD_LOGFILEプロシージャは、LogMinerに解析対象のREDOログファイルを追加するもので、それぞれのREDOを以下のコマンドで追加しています。
```sql
BEGIN
    DBMS_LOGMNR.ADD_LOGFILE(
        LOGFILENAME => '/u02/oradata/CDB1/redo03.log',
        OPTIONS => DBMS_LOGMNR.NEW
    );
    DBMS_LOGMNR.ADD_LOGFILE(
        LOGFILENAME => '/u02/oradata/CDB1/redo02.log',
        OPTIONS => DBMS_LOGMNR.ADDFILE
    );
    DBMS_LOGMNR.ADD_LOGFILE(
        LOGFILENAME => '/u02/oradata/CDB1/redo01.log',
        OPTIONS => DBMS_LOGMNR.ADDFILE
    );
END;
/
```
※補足：REDOのパスは以下のSQLコマンドで確認してます。

```sql
SELECT MEMBER FROM V$LOGFILE;
```
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/e44c9771-e84f-1511-820a-084f8b19da5b.png)

## 解析してみる
**1. 解析の開始**
以下のコマンドで解析を開始します。これは、LogMinerを起動してREDOログファイルの解析を開始するためのコマンドです。
```sql
EXEC DBMS_LOGMNR.START_LOGMNR(DictFileName => '/u01/app/oracle/pudding_logmnr_dict.ora');
```

**2. REDOとUNDOの確認**
V$LOGMNR_CONTENTSビューを使用してREDOとUNDOの中身を確認します。</br>
最初の実行では正しく結果が表示されないことがあったので、2回実行しました。１回目に出力されなかった原因は調べても良く分からなく、内部的にキャッシュか何かがあるんだとうか。。。
2回目の実行は「EXEC DBMS_LOGMNR.END_LOGMNR;」を使用して１回解析を止めています。また、テーブル作成のSQLは実行してません。

```sql:１回目
SELECT 
    TO_CHAR(TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS') AS TIMESTAMP,
    SQL_REDO,
    SQL_UNDO
FROM 
    V$LOGMNR_CONTENTS
WHERE 
    TABLE_NAME = 'EIYOU'
ORDER BY TIMESTAMP;
```

```sql:２回目
EXEC DBMS_LOGMNR.END_LOGMNR;

EXEC DBMS_LOGMNR_D.BUILD(dictionary_filename => 'pudding_logmnr_dict.ora', dictionary_location => 'LOGMNR_DIR');
BEGIN
    DBMS_LOGMNR.ADD_LOGFILE(
        LOGFILENAME => '/u02/oradata/CDB1/redo03.log',
        OPTIONS => DBMS_LOGMNR.NEW
    );
    DBMS_LOGMNR.ADD_LOGFILE(
        LOGFILENAME => '/u02/oradata/CDB1/redo02.log',
        OPTIONS => DBMS_LOGMNR.ADDFILE
    );
    DBMS_LOGMNR.ADD_LOGFILE(
        LOGFILENAME => '/u02/oradata/CDB1/redo01.log',
        OPTIONS => DBMS_LOGMNR.ADDFILE
    );
END;
/

EXEC DBMS_LOGMNR.START_LOGMNR(DictFileName => '/u01/app/oracle/pudding_logmnr_dict.ora');

SELECT 
    TO_CHAR(TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS') AS TIMESTAMP,
    SQL_REDO,
    SQL_UNDO
FROM 
    V$LOGMNR_CONTENTS
WHERE 
    TABLE_NAME = 'EIYOU'
ORDER BY TIMESTAMP;
```

↓は実行結果のキャプチャとそれを表に起こしたものです。
![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/d24f56b1-f313-8cd9-b540-76fba1b7a1bc.png)

|TIMEATAMP|SQL_REDO|SQL_UNSO|
| ---- | ---- | ---- |
|2024-07-21 10:00:36|	"CREATE TABLE eiyou (    id NUMBER PRIMARY KEY,    name VARCHAR2(50));"	|(null)
|2024-07-21 10:00:37|	insert into "SYS"."EIYOU"("ID","NAME") values ('2','Pudding 2');|	delete from "SYS"."EIYOU" where "ID" = '2' and "NAME" = 'Pudding 2' and ROWID = 'AAASF2AABAAAeXXXXXX';
|2024-07-21 10:00:37|	insert into "SYS"."EIYOU"("ID","NAME") values ('1','Pudding 1');|	delete from "SYS"."EIYOU" where "ID" = '1' and "NAME" = 'Pudding 1' and ROWID = 'AAASF2AABAAAeXXXXXX';

**3. 確認結果**
REDOログには実行したINSERT文が記録され、UNDOログにはそれを取り消すDELETE文が記録されていました。</br>
INSERTしか実行していなくても、自動的にUNDO用のコマンドが記録されています。
また、CREATE TABLEのようなDDL（データ定義言語）操作は、UNDO情報が生成されないです。UNDO情報は主にDML（データ操作言語）の例えばINSERT、UPDATE、DELETEなどで使用されるためです。

## まとめ
LogMinerを使用することで、OracleデータベースのREDOログとUNDOログの中身を確認することができました。
うまく進まない箇所もありましたがディレクトリオブジェクトやプロシージャのあたりについても理解を深めることができ、実際に手を動かすことで有益な知識を得られたと思います。