Oracle 11.2.0.4 Data Pump 恢复 T_S_BIZ_LOG 时 ORA-07445:一次 klxprParseRow 崩溃排查记录#
最近处理一次 Oracle 11.2.0.4 数据库迁移。
源库使用 ASM,目标库是普通单机文件系统,需要通过 Data Pump 将源库用户 gzdb 恢复到测试库的 gzdb。
表空间同时进行:
USERS → YSSUCO整体恢复过程中,大部分对象都可以正常导入。
但是有一张表始终非常奇怪:
T_S_BIZ_LOG只要恢复到这张表的数据阶段,Data Pump Worker 就可能直接崩溃。
不是普通的:
ORA-39083
ORA-31684
ORA-39151而是数据库后台进程直接出现:
ORA-07445
SIGSEGV最终定位到:
klxprParseRow()这次排查比较有意思,因为后来在 Oracle 后续版本的 Bug Fix 列表中,发现了一个与这个函数完全对应的 Bug:
31670014
AIM ORA-7445 [KLXPRPARSEROW] - KLXPRPARSEROW因此把整个过程记录下来。
一、环境#
本次环境:
Oracle Database 11.2.0.4.0
Linux x86_64
64-bit
源库:
gzdb
目标库:
gzdb
源库:
ASM
目标库:
单机文件系统源库通过:
expdp "/ as sysdba" \
cluster=N \
dumpfile=gzdb_full-${vdate}.dmp \
full=y \
parallel=4 \
logfile=gzdb_full-${vdate}.log \
directory=expdpbak \
compression=all生成全库 Data Pump 文件。
本次实际使用:
gzdb_full-2026-09-17.dmp目标库导入:
gzdb
↓
gzdb并进行:
USERS
↓
YSSUCO表空间映射。
二、最开始怀疑是不是普通的 Data Pump 导入问题#
最开始执行:
impdp "'/ as sysdba'" \
directory=BACKUP1 \
dumpfile=gzdb_full-2026-09-17.dmp \
logfile=20260922-1119.log \
schemas=gzdb \
remap_schema=gzdb:gzdb \
remap_tablespace=USERS:YSSUCO \
parallel=16 \
cluster=N \
exclude=STATISTICS过程中出现了很多看起来比较吓人的信息:
ORA-31684 USER already exists
ORA-39151
ORA-39083
ORA-02304其中最明显的是 TYPE 创建失败:
ORA-39083: Object type TYPE failed to create
ORA-02304: invalid object identifier literal一开始很容易把这些错误和后面的表恢复失败联系起来。
实际上后来发现,这两类问题应该分开看。
三、ORA-02304:TYPE OID 问题#
源库有一批用户自定义 TYPE。
例如:
STR_SPLIT
MAP_OBJECT_N2N
MAP_OBJECT
FEE_ROW_TYPE
ROW_TYPE
OBJ_TABLE
PORT_LIST_TYPE
DAE_ROW_TYPE
gz_CONCAT_IM
MAP_OBJECT_CLOB
OBJ_PARAMS
SPLITTYPE
VARTABLETYPE2
VARTABLETYPE
T_MAP_OBJECT_N2N
T_MAP_OBJECT
T_FEE_TYPE
T_MAP_OBJECT_CLOB
TAB_PARAMSData Pump 导入的时候生成类似:
CREATE TYPE ...
OID '2A7B2DF7A6C13042E0630408A8C066D4'
...目标数据库直接执行这种 OID 创建:
CREATE TYPE TEST_OID
OID '2A7B2DF7A6C13042E0630408A8C066D4'
AS TABLE OF VARCHAR2(4000);返回:
ORA-02304
invalid object identifier literal后来通过 SQLFILE 把 TYPE DDL 提取出来,并去掉:
OID '...'之后 19 个 TYPE 都可以正常创建。
这说明:
TYPE OID 问题确实存在。
但是它和后面的:
klxprParseRow()
SIGSEGV并不是同一个问题。
四、真正让 Data Pump 崩溃的是 T_S_BIZ_LOG#
真正奇怪的是:
Data Pump 并不是简单报告某一行数据错误。
而是 Worker 进程直接崩了。
trace 文件:
orcl_dw00_15519.trc其中最关键的信息:
Oracle Database 11.2.0.4.0以及:
DW00
Data Pump Worker最终异常:
Exception [type: SIGSEGV, SI_KERNEL(general_protection)]
[ADDR:0x0]
[PC:0x1F22D68, klxprParseRow()+4516]
ORA-07445: exception encountered:
core dump [klxprParseRow()+4516]
[SIGSEGV]这就不是普通 SQL 错误了。
这是 Oracle Server 进程自身访问了非法内存。
五、第一次看到的时候,很容易怀疑并行度#
当时 Data Pump 使用:
PARALLEL=16所以第一反应自然是:
是不是并行太高,把 Oracle 11.2.0.4 搞崩了?
于是继续降低并行。
甚至针对这张表单独执行:
impdp "'/ as sysdba'" \
directory=BACKUP1 \
dumpfile=gzdb_full-2026-09-17.dmp \
logfile=t_s_biz_log_restore_20260922.log \
tables=gzdb.T_S_BIZ_LOG \
remap_schema=gzdb:gzdb \
remap_tablespace=USERS:YSSUCO \
parallel=1 \
cluster=N重点来了:
PARALLEL=1还是崩。
而且仍然是:
klxprParseRow()这一步基本排除了:
PARALLEL=16是主要原因。
六、Data Pump 实际执行到了什么地方?#
trace 中可以看到类似:
INSERT /*+ APPEND PARALLEL("T_S_BIZ_LOG",1)+*/
INTO RELATIONAL("gzdb"."T_S_BIZ_LOG" NOT XMLTYPE)
...
SELECT ...
FROM "ET$0CEDD59B0001" KU$并且 SQL 中包含:
C_LOG_DETAIL
C_PLAIN_CONTENT这两个字段。
也就是说,真正发生崩溃的位置,是:
Data Pump
↓
TABLE_DATA
↓
Data Pump Worker
↓
直接装载数据
↓
T_S_BIZ_LOG
↓
klxprParseRow()
↓
SIGSEGV
↓
ORA-07445而不是:
建表失败也不是:
建索引失败更不是:
表空间不存在七、T_S_BIZ_LOG 到底是什么表?#
这张表本身并不是普通的小表。
大约:
2,260,121 rows两个 CLOB:
C_LOG_DETAIL
C_PLAIN_CONTENT其中:
C_LOG_DETAIL
最大长度约 655 KB
C_PLAIN_CONTENT
最大长度约 7.6 MB源库统计:
C_LOG_DETAIL 非 NULL:
2,224,651
C_PLAIN_CONTENT 非 NULL:
2,221,263其中:
C_PLAIN_CONTENT > 1 MB大约:
990 rows甚至发现:
C_PLAIN_CONTENT > 7 MB还有:
53 rows例如:
C_IDEN LOG_LEN PLAIN_LEN
4189815 627198 7604238
4189807 627198 7604238
4189836 627096 7604179
4189889 626912 7604088因此这张表的特点非常明显:
220 万+
+
两个 BASICFILE CLOB
+
大量大 CLOB
+
单行 CLOB 最大约 7.6 MB这和普通业务表完全不是一个级别的数据结构。
八、是不是 CLOB 本身坏了?#
这是当时非常重要的一个问题。
检查:
SELECT COUNT(*)
FROM gzdb.T_S_BIZ_LOG;结果:
2260121同时检查:
SELECT
MAX(DBMS_LOB.GETLENGTH(C_LOG_DETAIL)),
MAX(DBMS_LOB.GETLENGTH(C_PLAIN_CONTENT))
FROM gzdb.T_S_BIZ_LOG;得到:
C_LOG_DETAIL
655438
C_PLAIN_CONTENT
7604238没有直接发现明显的 LOB 损坏证据。
而且普通 SQL 可以读取这些数据。
所以不能简单得出:
CLOB 数据坏了。
更准确的说法应该是:
这张表的数据特征触发了 Oracle 11.2.0.4 Data Pump 数据装载路径中的异常。
九、最关键的实验:把 T_S_BIZ_LOG 排除#
后来做了一个非常重要的验证。
Data Pump 正常恢复整个 Schema,但是:
EXCLUDE=T_S_BIZ_LOG也就是:
其他所有对象继续恢复
T_S_BIZ_LOG 暂时不恢复使用 parfile:
DIRECTORY=BACKUP1
DUMPFILE=gzdb_full-2026-09-17.dmp
LOGFILE=gzdb_without_bizlog_20260922.log
SCHEMAS=gzdb
REMAP_SCHEMA=gzdb:gzdb
REMAP_TABLESPACE=USERS:YSSUCO
PARALLEL=16
CLUSTER=N
EXCLUDE=TABLE:"IN ('T_S_BIZ_LOG')"结果:
完整 Schema 恢复完成没有再发生:
DW00 SIGSEGV
ORA-07445
klxprParseRow()这就是整个排查过程中最有价值的一次 A/B Test。
十、因此可以把问题范围缩到非常小#
整个过程形成了一个非常清晰的矩阵:
| 测试 | 结果 |
|---|---|
| 整个 Schema 导入 | 失败 |
| 排除 T_S_BIZ_LOG | 成功 |
| 单独导入 T_S_BIZ_LOG | 失败 |
| PARALLEL=16 | 失败 |
| PARALLEL=1 | 仍然失败 |
| 普通 SQL 查询 T_S_BIZ_LOG | 正常 |
| 其他表 Data Pump | 正常 |
| TYPE 手工创建 | 可以绕过 OID 问题 |
| 删除 T_S_BIZ_LOG 后重新导入其他对象 | 成功 |
所以基本可以确定:
不是整个 Dump 文件坏了
不是整个 Schema 坏了
不是简单的表空间不足
不是单纯 PARALLEL=16
不是普通用户权限问题
不是所有 CLOB 都无法恢复而是:
T_S_BIZ_LOG
↓
特定数据 + CLOB
↓
Data Pump TABLE_DATA
↓
Oracle 11.2.0.4 内部处理
↓
klxprParseRow()
↓
SIGSEGV十一、然后搜到了一个非常有意思的 Oracle Bug#
这一步是整个案例最值得记录的地方。
继续搜索:
klxprParseRow Oracle发现 Oracle 后续版本的 Bug Fix 列表中出现:
31670014
AIM ORA-7445 [KLXPRPARSEROW] - KLXPRPARSEROWOracle 19.10 RU 的 Bug Fix 列表中明确列出了:
31670014 | AIM ORA-7445 [KLXPRPARSEROW] - KLXPRPARSEROW这与我们实际 trace 中:
ORA-07445
[klxprParseRow()+4516]函数名称完全对应。(DBA - Rodrigo Jorge)
这个发现非常重要。
十二、但是不能简单说“就是 Bug 31670014”#
这里必须谨慎。
目前公开资料能够证明:
Oracle 后续版本存在 Bug 31670014并且:
Bug 31670014的描述就是:
AIM ORA-7445 [KLXPRPARSEROW]同时我们的:
Oracle 11.2.0.4trace:
ORA-07445 [klxprParseRow()+4516]完全对应函数。
但是:
31670014是否直接 backport 到某个 11.2.0.4 PSU/BP/RU?
以及:
本案例具体是否就是 31670014仅凭公开 Bug Fix 列表还不能 100% 下结论。
Oracle 内部 Bug 资料很多需要 MOS 权限才能看到完整:
Cause
Affected Versions
Fixed Versions
Patch
Backport
Workaround因此本文更严谨的表述应该是:
本次事故与 Oracle 后续公开 Bug Fix 列表中的 Bug 31670014(KLXPRPARSEROW / ORA-7445)具有高度一致的函数级特征,但目前无法仅凭公开资料确认该 11.2.0.4 环境中的问题就是该 Bug 的 backport 版本。
这样记录比较靠谱。
十三、以前也有人遇到 Data Pump + ORA-07445#
这也不是第一次有人遇到:
impdp
+
ORA-07445Oracle 官方社区可以找到类似案例。
例如一个 2015 年的案例:
source: 11.2.0.4
target: 11.2.0.1使用 impdp 恢复过程中直接出现:
ORA-07445并且是在 Data Pump TABLE_DATA 处理过程中发生。(Oracle Forums)
另外更早的 Oracle 社区案例也有:
Oracle 11.2.0.2
Data Pump restore
ORA-07445最终向 Oracle Support 提交 SR 后,建议升级/打补丁,或者绕开 Data Pump。(Oracle Forums)
这说明:
Data Pump
+
Oracle 11g
+
ORA-07445本身并不是一个完全没有先例的组合。
十四、Oracle 官方对 ORA-07445 的定义#
Oracle 自己对 ORA-07445 的解释也很明确。
ORA-07445 本质是:
Operating System Exception也就是 Oracle Server 进程在执行内部代码时触发了操作系统级异常。
常见原因包括:
Bad Data
Misconfiguration
Oracle BugOracle 建议通过:
alert.log
trace
ADR
ORA-07445 diagnostic information进行定位。(Oracle Blogs)
所以遇到这种错误,最重要的一件事情不是继续不停地改:
PARALLEL=16
PARALLEL=8
PARALLEL=4
PARALLEL=1而是:
看 trace尤其是:
ORA-07445
[函数名()+偏移]这一部分。
十五、为什么普通的 Data Pump 日志反而不容易看出问题?#
这是这次事故非常容易误判的地方。
Data Pump log 最后可能只显示:
Processing object type ...或者:
import job stopped due to fatal error甚至没有明确告诉你:
哪一行数据真正有价值的信息反而在:
$ORACLE_BASE/diag/rdbms/.../trace/例如本次:
orcl_dw00_15519.trc里面才出现:
DW00
Data Pump Worker以及:
klxprParseRow()和:
ORA-07445
SIGSEGV所以:
Data Pump log 只能告诉你“恢复失败了”,trace 才告诉你“Oracle 自己崩在哪里”。
十六、为什么 T_S_BIZ_LOG 特别值得怀疑?#
这张表有几个非常特殊的特征:
220 万+ 行两个:
CLOB而且:
C_PLAIN_CONTENT单行最大:
7,604,238约:
7.25 MB另外还有接近:
1000行超过:
1 MBOracle 11g Data Pump 对 LOB 数据处理本身就比普通 VARCHAR2 数据复杂。
Oracle 11g Data Pump 文档也专门提供了与 XML/CLOB 数据相关的 Data Pump 数据选项;另外公开资料中也有专门针对 Data Pump LOB 导入/导出性能和处理路径的诊断资料。(Oracle Docs)
因此从工程角度看:
T_S_BIZ_LOG
+
大 CLOB
+
11.2.0.4
+
Data Pump TABLE_DATA
+
klxprParseRow确实是一个非常值得重点怀疑的组合。
但仍然不能简单等价成:
CLOB = 一定导致 Bug目前没有足够证据这么下结论。
十七、最终恢复策略#
既然已经证明:
其他 9850+ 张表可以正常恢复最合理的方案就是:
Data Pump
↓
完整恢复 Schema
↓
排除 T_S_BIZ_LOG
↓
T_S_BIZ_LOG 单独处理也就是:
恢复结构
+
恢复其他对象
+
T_S_BIZ_LOG 数据单独搬运十八、T_S_BIZ_LOG 不一定非要再用 Data Pump#
这张表完全可以采用:
Database Link
+
普通 INSERT例如:
CREATE DATABASE LINK SRC_gzdb
CONNECT TO gzdb
IDENTIFIED BY "源库密码"
USING '源库TNS服务名';然后:
SELECT COUNT(*)
FROM gzdb.T_S_BIZ_LOG@SRC_gzdb;确认 DB Link 正常。
再进行分批:
INSERT INTO gzdb.T_S_BIZ_LOG
(
C_IDEN,
C_FUN_CODE,
C_IDF_CODE,
D_TRADE,
C_PORT_CODE,
C_ITEM_CODE,
C_ITEM_NAME,
C_RESULT,
D_UPDATE,
C_UPDATE_BY,
C_UPDATE_TIME,
C_LOG_DETAIL,
C_PLAIN_CONTENT,
C_FUNRELA_ID,
C_DISPATCH_ID,
C_START_TIME,
C_END_TIME,
C_MES_TEXT,
C_TASK_CATEGORY,
C_PROCESS_INST_ID,
C_TASK_INST_ID,
C_EXTRA_INFO,
C_IP,
C_USE_TIME,
C_PLAN_CODE,
C_ITEM_EXTRA_INFO,
C_NODATA_TYPE
)
SELECT
C_IDEN,
C_FUN_CODE,
C_IDF_CODE,
D_TRADE,
C_PORT_CODE,
C_ITEM_CODE,
C_ITEM_NAME,
C_RESULT,
D_UPDATE,
C_UPDATE_BY,
C_UPDATE_TIME,
C_LOG_DETAIL,
C_PLAIN_CONTENT,
C_FUNRELA_ID,
C_DISPATCH_ID,
C_START_TIME,
C_END_TIME,
C_MES_TEXT,
C_TASK_CATEGORY,
C_PROCESS_INST_ID,
C_TASK_INST_ID,
C_EXTRA_INFO,
C_IP,
C_USE_TIME,
C_PLAN_CODE,
C_ITEM_EXTRA_INFO,
C_NODATA_TYPE
FROM gzdb.T_S_BIZ_LOG@SRC_gzdb
WHERE ORA_HASH(C_IDEN, 19) = 0;
COMMIT;然后:
0
1
2
...
19分 20 批。
如果单批仍然压力比较大,可以直接改成:
0 ~ 39也就是 40 批。
十九、为什么 DB Link + INSERT 值得尝试?#
因为它和 Data Pump 当前失败的路径不是完全相同的。
Data Pump 当前走的是:
Data Pump Worker
↓
TABLE_DATA
↓
direct path
↓
APPEND
↓
klxprParseRow()
↓
SIGSEGV而普通:
INSERT INTO ...
SELECT ...
FROM ...@DBLINK;属于普通 SQL 数据迁移路径。
所以可以把问题从:
Oracle Data Pump 内部数据装载切换成:
Oracle SQL 执行层如果这样能够成功:
2,260,121 rows
+
两个 CLOB那么就进一步证明:
数据本身并非无法读取,主要问题集中在 Data Pump 的数据装载路径。
这也是本次案例最有价值的最终验证实验。
二十、不要直接一把梭 220 万行#
第一次一定建议:
INSERT ...
SELECT ...
WHERE ORA_HASH(C_IDEN, 19) = 0
AND ROWNUM <= 1000;
COMMIT;先验证:
1000 行
+
CLOB
+
DB Link
+
目标表全部正常。
然后:
10000再:
100000最后才进行完整批次。
因为:
7 MB CLOB
+
几十万行一次事务的:
UNDO
REDO
TEMP
网络传输
LOB 写入都不能小看。
二十一、这次事故最后的结论#
这次问题最终没有表现为传统意义上的:
ORA-01653
表空间不足也不是:
ORA-39083
对象创建失败而是:
Data Pump Worker
↓
TABLE_DATA
↓
T_S_BIZ_LOG
↓
klxprParseRow()
↓
SIGSEGV
↓
ORA-07445同时:
PARALLEL=16降低到:
PARALLEL=1问题仍然存在。
而:
EXCLUDE T_S_BIZ_LOG之后整个 Schema 可以正常恢复。
因此目前最合理的判断是:
Oracle 11.2.0.4 的 Data Pump 在处理这张包含两个大型 BASICFILE CLOB 的表时,触发了
klxprParseRow()内部异常。公开资料中还可以找到 Oracle 后续版本针对KLXPRPARSEROW/ ORA-7445 的 Bug 31670014,因此高度怀疑属于 Oracle 内部 Bug 或特定数据模式触发的内部缺陷,但不能仅凭公开资料确认本次事故就是 Bug 31670014。
二十二、以后遇到类似问题,建议按照这个顺序排查#
以后碰到:
impdp突然:
fatal error不要第一时间反复修改:
PARALLEL
TABLE_EXISTS_ACTION
REMAP_TABLESPACE建议直接:
1. 找 alert#
grep -i "ORA-07445" alert*.log2. 找 trace#
find $ORACLE_BASE/diag -name "*.trc" -mmin -603. 找函数#
重点看:
ORA-07445:
[xxx()+offset]例如本案例:
[klxprParseRow()+4516]4. 看 Current SQL#
确认:
SQL_ID
TABLE_NAME
MODULE
ACTION5. 降到 PARALLEL=1#
不是为了“解决”,而是为了验证:
是不是并行导致6. 单独导入嫌疑表#
例如:
impdp ... tables=gzdb.T_S_BIZ_LOG parallel=17. 排除嫌疑表重新恢复 Schema#
如果:
排除以后成功基本就可以锁定对象。
8. 最后考虑绕过 Data Pump#
例如:
DB Link
+
INSERT SELECT或者:
SQL*Loader甚至:
中间文件二十三、这次最重要的经验#
Oracle 数据库迁移里有一个非常容易被忽视的问题:
Data Pump 报错,不代表数据一定坏了。
尤其是:
ORA-00600
ORA-07445
SIGSEGV
core dump这种级别的问题。
如果普通 SQL 能正常读取:
SELECT
DBMS_LOB.GETLENGTH
DBMS_LOB.SUBSTR而 Data Pump 在特定表的数据装载阶段直接把 Worker 打崩,那么就应该开始怀疑:
Oracle 内部 Bug而不是继续无限纠结:
是不是 dump 文件坏了?
是不是表空间不够?
是不是 parallel 太高?
是不是权限不够?本次案例尤其典型:
220 万行
+
两个 CLOB
+
最大 7.6 MB
+
Oracle 11.2.0.4
+
Data Pump
+
klxprParseRow
+
SIGSEGV最后通过:
排除 T_S_BIZ_LOG让整个 Schema 恢复成功,再把这张表单独处理。
这可能比为了“一次性 Data Pump 完整恢复”反复折腾更实际。
参考资料#
Oracle 官方对 ORA-07445 的说明认为,这类错误本质上是 Oracle 代码触发的操作系统级异常,常见根因包括坏数据、配置问题以及 Oracle Bug。(Oracle Blogs)
Oracle 社区存在多个 Data Pump + ORA-07445 的历史案例,其中包括 Oracle 11.2.x 环境。(Oracle Forums)
Oracle 19.10 Bug Fix 列表明确记录:
31670014
AIM ORA-7445 [KLXPRPARSEROW] - KLXPRPARSEROW与本次 klxprParseRow() 崩溃函数名高度一致。(DBA - Rodrigo Jorge)
最终处理路线#
本案例最终采用:
gzdb
│
├── Data Pump
│ │
│ ├── 其他对象 ─────────→ gzdb
│ │
│ └── T_S_BIZ_LOG ─────→ 排除
│
└── DB Link + INSERT SELECT
│
↓
T_S_BIZ_LOG这种方案不漂亮。
但数据库恢复最重要的往往不是:
“一条命令全部恢复”而是:
先把能恢复的恢复完
再把有问题的对象隔离
最后针对问题对象单独处理对于老版本 Oracle,尤其是:
11.2.0.4这种已经非常成熟但内部历史包袱也很多的版本,这种思路往往比死磕 Data Pump 更有效。
一个表把整个数据库恢复拖死,不如把这个表单独拎出来。