Oracle LogMiner 日志挖掘:原理、步骤、可执行脚本与结果解析


一、LogMiner 原理

1.1 本质

Oracle 的 Redo 日志记录的是物理变更向量(Change Vector):数据块地址(RDBA)、操作码、列偏移、前后镜像、SCN、事务 ID(XID)等,本身是二进制,人不可读。

LogMiner 做的是**"物理 → 逻辑"的翻译**:

复制代码
Redo/归档日志(二进制 change vector)
        │  ① 按 SCN / 事务顺序读取
        │  ② 用数据字典把 OBJ# / COL# 翻译成 表名 / 列名
        │  ③ 按事务重组、拼接行变更
        ▼
V$LOGMNR_CONTENTS(可读的逻辑 SQL)
        ├── SQL_REDO  → 原始操作(重放用,如 DELETE FROM T WHERE ...)
        └── SQL_UNDO  → 反向操作(回滚用,如 INSERT INTO T VALUES (...))

1.2 三个必备要素

要素 说明
日志文件 在线 Redo 或归档日志(生产挖掘建议只用归档日志)
数据字典 三种来源:①在线目录 DICT_FROM_ONLINE_CATALOG(最常用,须在源库执行)②提取到 Redo 流 STORE_IN_REDO_LOGS ③平面文件 STORE_IN_FLAT_FILE(跨库分析用)
分析会话 挖掘结果存放在发起会话的 PGA 中,会话断开即丢失

1.3 关键机制与限制

  • 必须开启补充日志 :只开归档、不开 SUPPLEMENTAL LOG DATA 时,DML 记录会缺失(例如 delete 10 条只挖到 6 条),且 SQL_UNDO 可能为 NULL。最小补充日志即可,主键补充日志能让 SQL_UNDO 的 WHERE 条件更精准。
  • DDL 只能看到 SQL_REDO ,没有 SQL_UNDO,DDL 回滚需人工处理。
  • 不支持/不完整 :部分 LOB、LONG、XMLType、ADT、链式行/迁移行的 DML 可能 SQL_REDO/SQL_UNDO 为 NULL 或 Unsupported。
  • 跨库分析 :分析库的 DB_BLOCK_SIZE 必须 ≥ 源库,平台、字符集需一致,且必须使用源库生成的字典。
  • 12c 及以上 CDB :LogMiner 必须在 CDB$ROOT 下执行,PDB 内执行会报错。
  • 不要把当前在线日志加入挖掘列表 ,否则 CTAS/查询 V$LOGMNR_CONTENTS 时容易触发 ORA-00310 / ORA-00334(递归重做导致日志切换,问题反复重演)。

二、标准步骤与命令(手工版)

sql 复制代码
-- 0. 环境检查
ARCHIVE LOG LIST;
SELECT supplemental_log_data_min, supplemental_log_data_pk FROM v$database;

-- 1. 开启补充日志(只需做一次,持续生效)
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;   -- 可选,回滚更精准

-- 2. 定位误操作时间窗内的归档日志
SELECT thread#, sequence#, first_time, next_time, name
  FROM v$archived_log
 WHERE name IS NOT NULL AND status = 'A'
   AND next_time  > TO_DATE('2026-10-23 10:00:00','YYYY-MM-DD HH24:MI:SS')
   AND first_time < TO_DATE('2026-10-23 10:30:00','YYYY-MM-DD HH24:MI:SS')
 ORDER BY thread#, sequence#;

-- 3. 添加日志(第一个用 NEW,后续用 ADDFILE)
EXEC DBMS_LOGMNR.ADD_LOGFILE('/arch/.../1_10506.dbf', DBMS_LOGMNR.NEW);
EXEC DBMS_LOGMNR.ADD_LOGFILE('/arch/.../1_10507.dbf', DBMS_LOGMNR.ADDFILE);

-- 4. 启动挖掘(同一会话内执行)
EXEC DBMS_LOGMNR.START_LOGMNR( -
       STARTTIME => TO_DATE('2026-10-23 10:00:00','YYYY-MM-DD HH24:MI:SS'), -
       ENDTIME   => TO_DATE('2026-10-23 10:30:00','YYYY-MM-DD HH24:MI:SS'), -
       OPTIONS   => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG + -
                    DBMS_LOGMNR.COMMITTED_DATA_ONLY + -
                    DBMS_LOGMNR.PRINT_PRETTY_SQL + -
                    DBMS_LOGMNR.SKIP_CORRUPTION);

-- 5. 查询结果(务必带过滤条件,否则极慢)
SELECT scn, timestamp, xid, username, operation, seg_owner, seg_name,
       sql_redo, sql_undo
  FROM v$logmnr_contents
 WHERE seg_owner = 'SCOTT' AND seg_name = 'EMP'
   AND operation IN ('INSERT','UPDATE','DELETE');

-- 6. 结束挖掘,释放 PGA
EXEC DBMS_LOGMNR.END_LOGMNR;

常用 START_LOGMNR 选项:

选项 作用
DICT_FROM_ONLINE_CATALOG 使用在线字典(源库执行)
COMMITTED_DATA_ONLY 只返回已提交事务,自动过滤回滚掉的事务
PRINT_PRETTY_SQL 输出带换行/缩进的可读 SQL
SKIP_CORRUPTION 跳过损坏的 redo 块,避免中断
NO_ROWID_IN_STMT WHERE 条件用主键代替 ROWID(需主键补充日志)
DDL_ONLY / CONTINUOUS_MINE 只挖 DDL / 持续挖掘(12c 后不推荐)

权限要求:LOGMINING(12c+)、SELECT ANY TRANSACTION、EXECUTE_CATALOG_ROLE,或直接 sysdba。


三、可执行脚本(复制保存为 logminer_mine.sh)

脚本自动完成:环境检查 → 按时间窗自动收集归档日志 → 添加并启动挖掘 → 结果落表 → 多维统计解析 → 自动拼接生成回滚脚本(处理 CSF 续行)→ 结束挖掘。

bash 复制代码
#!/usr/bin/env bash
###############################################################################
# logminer_mine.sh ------ Oracle LogMiner 归档日志挖掘 + 结果解析 + 回滚脚本生成
# 适用:Oracle 11gR2 / 12c / 18c / 19c / 21c(CDB 请在 CDB$ROOT 执行)
# 用法:
#   ./logminer_mine.sh "user/pass@tns" "2026-10-23 10:00:00" "2026-10-23 10:30:00"
#   ./logminer_mine.sh "/ as sysdba"  "2026-10-23 10:00:00" "2026-10-23 10:30:00" "SCOTT.EMP"
# 参数:
#   $1 连接串   $2 起始时间   $3 结束时间
#   $4 可选:对象过滤 OWNER.TABLE
#   $5 可选:输出目录(默认 $HOME/logminer_out)
###############################################################################
set -euo pipefail

CONN="${1:?用法: $0 \"user/pass@tns\" \"开始时间\" \"结束时间\" [OWNER.TABLE] [输出目录]}"
START_TIME="${2:?缺少开始时间}"
END_TIME="${3:?缺少结束时间}"
OBJ="${4:-}"
OUT_DIR="${5:-$HOME/logminer_out}"

mkdir -p "$OUT_DIR"
TS=$(date +%Y%m%d_%H%M%S)
STAGE="LOGMNR_STAGE_${TS}"
UNDO_TAB="LOGMNR_UNDO_${TS}"
LOG_FILE="$OUT_DIR/logminer_${TS}.log"
REPORT_FILE="$OUT_DIR/report_${TS}.txt"
UNDO_FILE="$OUT_DIR/undo_${TS}.sql"

# 对象过滤条件
OBJ_WHERE=""
if [ -n "$OBJ" ]; then
  case "$OBJ" in
    *.*) O="${OBJ%%.*}"; T="${OBJ##*.}" ;;
    *)   O="";           T="$OBJ" ;;
  esac
  if [ -n "$O" ]; then
    OBJ_WHERE=" AND SEG_OWNER='${O^^}' AND SEG_NAME='${T^^}'"
  else
    OBJ_WHERE=" AND SEG_NAME='${T^^}'"
  fi
fi

echo "[INFO] 时间窗 : ${START_TIME} ~ ${END_TIME}"
echo "[INFO] 对象过滤: ${OBJ:-<全部用户对象>}"
echo "[INFO] 输出目录: ${OUT_DIR}"

sqlplus -s "$CONN" <<SQLEOF > "$LOG_FILE" 2>&1
SET ECHO OFF
SET FEEDBACK ON
SET VERIFY OFF
SET DEFINE OFF
SET PAGESIZE 300
SET LINESIZE 400
SET TRIMSPOOL ON
SET LONG 1000000
SET LONGCHUNKSIZE 1000000
SET SERVEROUTPUT ON SIZE UNLIMITED FORMAT WRAPPED
WHENEVER SQLERROR EXIT FAILURE

ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_DATE_LANGUAGE='AMERICAN';

SPOOL "${REPORT_FILE}"

PROMPT ################ 1. 环境检查 ################
SELECT NAME AS DB_NAME, LOG_MODE, DATABASE_ROLE, CDB,
       SUPPLEMENTAL_LOG_DATA_MIN AS SUP_MIN,
       SUPPLEMENTAL_LOG_DATA_PK  AS SUP_PK
  FROM V\$DATABASE;

SELECT OWNER, OBJECT_NAME, OBJECT_TYPE, STATUS
  FROM DBA_OBJECTS
 WHERE OBJECT_NAME IN ('DBMS_LOGMNR','DBMS_LOGMNR_D')
   AND OWNER = 'SYS';

PROMPT ################ 2. 待分析归档日志 ################
SELECT THREAD#, SEQUENCE#, FIRST_TIME, NEXT_TIME, NAME
  FROM V\$ARCHIVED_LOG
 WHERE NAME IS NOT NULL AND STATUS = 'A'
   AND NEXT_TIME  > TO_DATE('${START_TIME}','YYYY-MM-DD HH24:MI:SS')
   AND FIRST_TIME < TO_DATE('${END_TIME}','YYYY-MM-DD HH24:MI:SS')
 ORDER BY THREAD#, SEQUENCE#;

PROMPT ################ 3. 添加日志并启动挖掘 ################
DECLARE
  v_first BOOLEAN := TRUE;
  v_cnt   PLS_INTEGER := 0;
BEGIN
  FOR r IN (
    SELECT DISTINCT name, thread#, sequence#
      FROM V\$ARCHIVED_LOG
     WHERE NAME IS NOT NULL AND STATUS = 'A'
       AND NEXT_TIME  > TO_DATE('${START_TIME}','YYYY-MM-DD HH24:MI:SS')
       AND FIRST_TIME < TO_DATE('${END_TIME}','YYYY-MM-DD HH24:MI:SS')
     ORDER BY thread#, sequence#
  ) LOOP
    BEGIN
      IF v_first THEN
        DBMS_LOGMNR.ADD_LOGFILE(LOGFILENAME => r.name, OPTIONS => DBMS_LOGMNR.NEW);
        v_first := FALSE;
      ELSE
        DBMS_LOGMNR.ADD_LOGFILE(LOGFILENAME => r.name, OPTIONS => DBMS_LOGMNR.ADDFILE);
      END IF;
      v_cnt := v_cnt + 1;
    EXCEPTION
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('跳过 ' || r.name || ' : ' || SQLERRM);
    END;
  END LOOP;

  IF v_cnt = 0 THEN
    RAISE_APPLICATION_ERROR(-20001, '指定时间窗内没有可用归档日志,请检查归档保留策略或时间范围');
  END IF;
  DBMS_OUTPUT.PUT_LINE('已添加归档日志数量: ' || v_cnt);
END;
/

BEGIN
  DBMS_LOGMNR.START_LOGMNR(
    STARTTIME => TO_DATE('${START_TIME}','YYYY-MM-DD HH24:MI:SS'),
    ENDTIME   => TO_DATE('${END_TIME}','YYYY-MM-DD HH24:MI:SS'),
    OPTIONS   => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG
               + DBMS_LOGMNR.COMMITTED_DATA_ONLY
               + DBMS_LOGMNR.PRINT_PRETTY_SQL
               + DBMS_LOGMNR.SKIP_CORRUPTION
  );
  DBMS_OUTPUT.PUT_LINE('START_LOGMNR 完成');
END;
/

PROMPT ---- 当前分析参数 ----
SELECT START_SCN, START_DATE, END_SCN, END_DATE, OPTIONS
  FROM V\$LOGMNR_PARAMETERS;

PROMPT ---- 已注册日志清单 ----
SELECT THREAD#, SEQUENCE#, LOW_SCN, NEXT_SCN, FILENAME
  FROM V\$LOGMNR_LOGS
 ORDER BY THREAD#, SEQUENCE#;

PROMPT ################ 4. 结果落地(同一会话内) ################
CREATE TABLE ${STAGE} AS
SELECT SCN,
       COMMIT_SCN,
       "TIMESTAMP"      AS CHANGE_TIME,
       START_TIMESTAMP  AS START_TIME,
       XID,
       USERNAME,
       SESSION#         AS SESSION_ID,
       OPERATION,
       SEG_OWNER,
       SEG_NAME,
       SEG_TYPE_NAME,
       SQL_REDO,
       SQL_UNDO,
       CSF,
       RS_ID,
       SSN,
       ROLLBACK         AS IS_ROLLBACK,
       SESSION_INFO,
       THREAD#          AS THREAD_ID,
       ROW_ID
  FROM V\$LOGMNR_CONTENTS
 WHERE OPERATION IN ('INSERT','UPDATE','DELETE','DDL')
   AND (SEG_OWNER IS NULL OR SEG_OWNER NOT IN
        ('SYS','SYSTEM','SYSMAN','DBSNMP','OUTLN','AUDSYS','XDB','MDSYS',
         'CTXSYS','ORDSYS','OLAPSYS','WMSYS','LBACSYS','APPQOSSYS',
         'GSMADMIN_INTERNAL','DVSYS','DVF','OJVMSYS','PUBLIC'))
${OBJ_WHERE};

BEGIN
  DBMS_LOGMNR.END_LOGMNR;
  DBMS_OUTPUT.PUT_LINE('END_LOGMNR 完成,PGA 已释放');
END;
/

PROMPT ################ 5. 挖掘结果解析 ################
PROMPT ---- 5.1 总览 ----
SELECT COUNT(*) AS TOTAL_ROWS,
       COUNT(DISTINCT XID) AS TX_COUNT,
       MIN(CHANGE_TIME) AS MIN_TIME,
       MAX(CHANGE_TIME) AS MAX_TIME
  FROM ${STAGE};

PROMPT ---- 5.2 按操作类型 ----
SELECT OPERATION, COUNT(*) AS CNT
  FROM ${STAGE}
 GROUP BY OPERATION
 ORDER BY CNT DESC;

PROMPT ---- 5.3 按对象 TOP 20 ----
SELECT * FROM (
  SELECT SEG_OWNER, SEG_NAME, OPERATION, COUNT(*) AS CNT
    FROM ${STAGE}
   GROUP BY SEG_OWNER, SEG_NAME, OPERATION
   ORDER BY CNT DESC
) WHERE ROWNUM <= 20;

PROMPT ---- 5.4 按数据库用户 ----
SELECT USERNAME, COUNT(*) AS CNT
  FROM ${STAGE}
 GROUP BY USERNAME
 ORDER BY CNT DESC;

PROMPT ---- 5.5 按小时分布 ----
SELECT TO_CHAR(CHANGE_TIME,'YYYY-MM-DD HH24') AS HOUR,
       OPERATION, COUNT(*) AS CNT
  FROM ${STAGE}
 GROUP BY TO_CHAR(CHANGE_TIME,'YYYY-MM-DD HH24'), OPERATION
 ORDER BY 1, 2;

PROMPT ---- 5.6 事务清单(按提交顺序)----
SELECT XID, USERNAME, COUNT(*) AS ROW_CNT,
       MIN(CHANGE_TIME) AS FIRST_TIME,
       MAX(CHANGE_TIME) AS LAST_TIME,
       MAX(COMMIT_SCN)  AS COMMIT_SCN
  FROM ${STAGE}
 GROUP BY XID, USERNAME
 ORDER BY COMMIT_SCN;

PROMPT ---- 5.7 变更明细(前 200 条)----
SELECT SCN, CHANGE_TIME, XID, USERNAME, OPERATION,
       SEG_OWNER, SEG_NAME, SQL_REDO
  FROM (SELECT * FROM ${STAGE} ORDER BY SCN, RS_ID, SSN)
 WHERE ROWNUM <= 200;

PROMPT ################ 6. 生成回滚脚本 ################
CREATE TABLE ${UNDO_TAB} (SEQ NUMBER, STMT CLOB);

DECLARE
  v_buf  CLOB;
  v_seq  PLS_INTEGER := 0;
  v_cnt  PLS_INTEGER := 0;
BEGIN
  FOR r IN (
    SELECT SQL_UNDO, CSF
      FROM ${STAGE}
     WHERE SQL_UNDO IS NOT NULL
       AND OPERATION IN ('INSERT','UPDATE','DELETE')
     ORDER BY COMMIT_SCN DESC, RS_ID DESC, SSN DESC   -- 逆序回滚
  ) LOOP
    IF v_buf IS NULL THEN
      v_buf := r.SQL_UNDO;
    ELSE
      v_buf := v_buf || r.SQL_UNDO;                    -- 拼接 CSF 续行
    END IF;

    IF NVL(r.CSF, 0) = 0 THEN
      v_seq := v_seq + 1;
      INSERT INTO ${UNDO_TAB}(SEQ, STMT)
      VALUES (v_seq,
              v_buf || CASE WHEN SUBSTR(v_buf, -1, 1) = ';' THEN '' ELSE ';' END);
      v_buf := NULL;
      v_cnt := v_cnt + 1;
    END IF;
  END LOOP;
  COMMIT;
  DBMS_OUTPUT.PUT_LINE('生成回滚语句条数: ' || v_cnt);
END;
/

SPOOL OFF

SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SPOOL "${UNDO_FILE}"
PROMPT -- ==========================================================
PROMPT -- LogMiner 回滚脚本(请务必完整审核后再执行)
PROMPT -- 生成时间: ${TS}
PROMPT -- 源时间窗: ${START_TIME} ~ ${END_TIME}
PROMPT -- 建议: 先备份相关表;SET AUTOCOMMIT OFF;分批执行并校验
PROMPT -- 注意: DDL 无 SQL_UNDO,需人工处理
PROMPT -- ==========================================================
PROMPT
SELECT STMT FROM ${UNDO_TAB} ORDER BY SEQ;
SPOOL OFF

PROMPT ################ 7. 完成 ################
PROMPT 明细表: ${STAGE}
PROMPT 回滚表: ${UNDO_TAB}
PROMPT 回滚脚本: ${UNDO_FILE}
PROMPT 报告: ${REPORT_FILE}
SQLEOF

echo "[OK] 日志: $LOG_FILE"
echo "[OK] 报告: $REPORT_FILE"
echo "[OK] 回滚脚本: $UNDO_FILE"
echo "[HINT] 明细表 ${STAGE} 保留用于复核,确认后可手工 DROP"

使用示例

bash 复制代码
chmod +x logminer_mine.sh

# 全库挖掘
./logminer_mine.sh "sys/Oracle_123@orcl" "2026-10-23 10:00:00" "2026-10-23 10:30:00"

# 只挖某张表
./logminer_mine.sh "/ as sysdba" "2026-10-23 10:00:00" "2026-10-23 10:30:00" "SCOTT.EMP"

四、挖掘后数据解析

4.1 V$LOGMNR_CONTENTS 核心字段解读

字段 含义 解析要点
SCN 变更发生时的 SCN 定位误操作精确时点的第一依据
COMMIT_SCN 事务提交 SCN 仅 COMMITTED_DATA_ONLY 下有意义,回滚排序用它
TIMESTAMP 变更时间 与业务日志时间对齐
XID 事务 ID 同一事务的所有行变更 XID 相同,用于按事务分组
USERNAME 执行用户 判断是应用账号还是人为操作
SESSION_INFO 会话信息(含终端、OS 用户等) 追溯"谁、从哪台机器"操作
OPERATION INSERT/UPDATE/DELETE/DDL/... 统计与过滤主维度
SEG_OWNER / SEG_NAME 对象属主 / 对象名 定位被改的表
SQL_REDO 原始操作 SQL 还原"当时做了什么"
SQL_UNDO 反向 SQL 生成回滚脚本的来源,DDL 为 NULL
CSF 续行标志(0/1) 1 表示该行 SQL 超 4000 字节,后续行继续,必须拼接
RS_ID / SSN 记录集 ID / 序号 与 SCN 一起保证同一事务内变更的精确顺序
ROLLBACK 是否被回滚 1 表示该事务最终回滚,不应恢复

4.2 判读顺序(建议)

  1. 看总览 :TOTAL_ROWS、TX_COUNT、时间范围是否落在误操作窗口内。
    • 若为 0 → 时间窗不对、归档缺失、或补充日志未开导致记录不全。
  2. 看对象 TOP:确认被影响的是不是目标表;若出现大量非预期表,说明时间窗过宽。
  3. 看事务清单 :找到 LAST_TIME 与误操作时间吻合、ROW_CNT 与影响行数吻合的 XID。
  4. 看明细 :核对 SQL_REDO 是否就是误操作语句;确认 USERNAME、SESSION_INFO。
  5. 看 SQL_UNDO 是否为空 :
    • 大量为 NULL → 检查 SUPPLEMENTAL_LOG_DATA_MIN 是否为 YES;主键补充日志是否开启。
  6. 生成并审核回滚脚本 :脚本已按 COMMIT_SCN DESC, RS_ID DESC, SSN DESC 逆序排列,保证同一事务内"后做的先回滚"。

4.3 回滚执行原则

  • 先备份 :CREATE TABLE T_BAK AS SELECT * FROM T;
  • 先小批量验证 :挑 1~2 条 SQL_UNDO 手工执行,确认 WHERE 条件命中的是目标行。
  • 关闭自动提交 :SET AUTOCOMMIT OFF;,核对行数后再 COMMIT。
  • 注意唯一约束/触发器:回滚 INSERT 可能触发业务触发器,必要时先禁用。
  • DDL 无 SQL_UNDO:被 drop/truncate 的表需用 Flashback Drop、RMAN 时间点恢复或手工重建。

4.4 补充分析 SQL(可直接在明细表上跑)

sql 复制代码
-- 某张表在时间窗内的完整变更时间线
SELECT scn, change_time, xid, username, operation, sql_redo
  FROM LOGMNR_STAGE_xxxxxx
 WHERE seg_owner='SCOTT' AND seg_name='EMP'
 ORDER BY scn, rs_id, ssn;

-- 找出影响行数最多的 10 个事务
SELECT * FROM (
  SELECT xid, username, seg_owner, seg_name, COUNT(*) cnt,
         MIN(change_time) first_time, MAX(change_time) last_time
    FROM LOGMNR_STAGE_xxxxxx
   GROUP BY xid, username, seg_owner, seg_name
   ORDER BY cnt DESC
) WHERE ROWNUM <= 10;

-- 导出某事务的回滚语句(手工指定 XID)
SELECT sql_undo FROM LOGMNR_STAGE_xxxxxx
 WHERE xid = '01001B00...' AND sql_undo IS NOT NULL
 ORDER BY commit_scn DESC, rs_id DESC, ssn DESC;

五、常见报错与规避

报错 原因 处理
ORA-01306 未 START_LOGMNR 就查 V$LOGMNR_CONTENTS,或已 END_LOGMNR 必须在同一会话先启动再查
ORA-01307 当前没有活动的 LogMiner 会话 检查是否已 END_LOGMNR 或会话断开
ORA-00310/ORA-00334 把当前在线日志加入挖掘,CTAS 产生递归重做 只挖归档日志;先 SWITCH LOGFILE 并确认该组为 INACTIVE
ORA-01284 归档文件不存在/权限不足(字典文件权限需 ≥ 750) 检查路径与文件权限
ORA-01308 用了 DICT_FROM_REDO_LOGS 但未设置 UTIL_FILE_DIR 改用在线目录或配置目录
SQL_UNDO 为 NULL / 记录缺失 未开启补充日志 ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
挖掘极慢 未加时间/SCN/表名过滤 在 START_LOGMNR 指定 STARTTIME/ENDTIME,查询再加 SEG_OWNER/SEG_NAME

生产环境提示:LogMiner 是 CPU/IO 密集型操作,建议在业务低峰执行;有条件时在 Data Guard 备库或独立分析库上进行(备库需具备相应字典与日志)。归档日志必须尚未被删除或覆盖,挖掘前先确认 V$ARCHIVED_LOG 中目标时段记录状态为 A。