Oracle 資料庫的所有變更都記錄在 Redo Log 中,但原始日誌格式晦澀難懂。LogMiner 是 Oracle 官方提供的唯一分析工具,類似於 tkprof 之於 Trace 文件,它能將二進制日誌重構為可讀的 SQL 語句。透過日誌分析,我們可以達成四大目標:追蹤邏輯變更、偵測並修正誤操作、事後審計、以及變更影響分析。
Redo Log 包含:資料庫變更歷史、操作類型(INSERT/UPDATE/DELETE/DDL)、對應的 SCN 號、執行操作的用戶資訊。LogMiner 會重構等價的 SQL_REDO 和 SQL_UNDO 語句(存放於 V$LOGMNR_CONTENTS 視圖)。注意:重構的是「等價語句」而非原始 SQL。 例如原始執行 DELETE FROM a WHERE c1 != 'cyx',LogMiner 可能重構為多條單行 DELETE 語句,因為資料庫記錄的是元操作(Row-level operations),同一條 SQL 在不同環境下影響的行數不同,記錄原始 SQL 無實際意義。
Redo Log 中記錄的是內部物件編號(Object ID、Column ID),而非名稱。為讓重構 SQL 可讀,LogMiner 需透過 DBMS_LOGMNR_D.BUILD() 提取資料字典,將編號映射為物件名稱。LogMiner 本身可不使用字典,但輸出將顯示 UNKNOWN.OBJ# 6197 和 COL 1 等內部代碼。
BUILD() 程序,用於提取字典。ADD_LOGFILE:新增/移除分析日誌檔START_LOGMNR:啟動分析,定義時間/SCN 窗口、指定字典檔END_LOGMNR:終止會話、釋放記憶體TX_AUDITING=TRUE 可記錄資料庫帳號。COMMITTED_DATA_ONLY 選項可按 SCN 順序返回已提交交易。DDL_DICT_TRACKING 選項自動比對初始日誌流與當前字典,即使表已修改或刪除,仍能返回正確 DDL。實例需啟動(至少 MOUNT 狀態)。設定 UTL_FILE_DIR 參數並確保 Oracle 對目錄有讀寫權限,用於存放字典檔。
SQL> SHOW PARAMETER utl_file_dir
NAME TYPE VALUE
utl_file_dir string /data6/cyx/logmnr
目錄路徑必須精確匹配,尾部斜線差異會導致錯誤。
EXEC DBMS_LOGMNR_D.BUILD(
DICTIONARY_FILENAME => 'dic.ora',
DICTIONARY_LOCATION => '/data6/cyx/logmnr'
);
若未設定 UTL_FILE_DIR 會報 ORA-01308。Windows 8.1.7 版本可能遇到 VARRAY 限制錯誤,需修改 $ORACLE_HOME/rdbms/admin/dbmslmd.sql 將 VARRAY(513) 改為 VARRAY(700) 並重新編譯套件。
EXEC DBMS_LOGMNR.ADD_LOGFILE(
LOGFILENAME => '/data6/cyx/rac1arch/arch_1_197.arc',
OPTIONS => DBMS_LOGMNR.NEW -- 建立新清單
);
EXEC DBMS_LOGMNR.ADD_LOGFILE(
LOGFILENAME => '/data6/cyx/rac1arch/arch_2_86.arc',
OPTIONS => DBMS_LOGMNR.ADDFILE -- 追加至清單
);
OPTIONS 可為 NEW、ADDFILE、REMOVEFILE。
-- 使用字典檔
EXEC DBMS_LOGMNR.START_LOGMNR(
DICTFILENAME => '/data6/cyx/logmnr/dic.ora'
);
-- 不使用字典檔
EXEC DBMS_LOGMNR.START_LOGMNR();
-- 指定時間窗口(需注意 NLS_DATE_FORMAT)
EXEC DBMS_LOGMNR.START_LOGMNR(
DICTFILENAME => '/data6/cyx/logmnr/dic.ora',
STARTTIME => TO_DATE('2003-09-21 09:39:00','YYYY-MM-DD HH24:MI:SS'),
ENDTIME => TO_DATE('2003-09-21 09:45:00','YYYY-MM-DD HH24:MI:SS')
);
亦可使用 STARTSCN/ENDSCN 定義 SCN 範圍。啟動後可查詢 SELECT DISTINCT TIMESTAMP FROM V$LOGMNR_CONTENTS 確認有效日誌時間範圍。
核心視圖為 V$LOGMNR_CONTENTS。RAC 環境下 V$LOGMNR_LOGS 會顯示不同 THREAD_ID。常見查詢場景:
SELECT TIMESTAMP, SQL_REDO FROM V$LOGMNR_CONTENTS WHERE UPPER(SQL_REDO) LIKE '%CREATE%'SESSION_INFO 欄位(含登入用戶、OS 用戶、機器名、終端、程式名)。結合登入觸發器記錄 Client IP:
CREATE OR REPLACE TRIGGER ON_LOGON_TRIGGER
AFTER LOGON ON DATABASE
BEGIN
DBMS_APPLICATION_INFO.SET_CLIENT_INFO(SYS_CONTEXT('USERENV','IP_ADDRESS'));
END;
則可透過 SESSION_INFO 中的 CLIENT_INFO 定位具體 IP。EXEC DBMS_LOGMNR.END_LOGMNR();
或直接退出 SQL*Plus 自動終止。
LogMiner 可分析舊版日誌,步驟:將 Oracle 8i 的 dbmslmd.sql 複製至 Oracle 8 主機執行建立套件,再用 DBMS_LOGMNR_D.BUILD 產生字典檔,將歸檔日誌與字典檔複製至 Oracle 8i/9i 主機,從「新增日誌檔」步驟開始分析。
限制條件:
SELECT TIMESTAMP, SQL_REDO
FROM V$LOGMNR_CONTENTS
WHERE UPPER(SQL_REDO) LIKE '%CREATE%';
某員工透過程式修改收費類型為免費。查詢更新 HMLX 表的操作:
SELECT SESSION_INFO, SQL_REDO
FROM V$LOGMNR_CONTENTS
WHERE UPPER(OPERATION) = 'UPDATE'
AND UPPER(SQL_REDO) LIKE '%HMLX%';
輸出範例:
SESSION_INFO: login_username=C CLIENT_INFO=10.16.98.26 OS_USERNAME=sz-xjs-chengyx MACHINE_NAME=GDTEL\SZ-XJS-CHENGYX
SQL_REDO: UPDATE "C"."HMLX" SET "NAME" = 'free' WHERE "NAME" = 'ncn.cn' AND ROWID = 'AAABhTAAFAAABRaAAE'
結合登入觸發器記錄的 IP,即可精準定位操作者。