PDB 还我一个炸弹(PDB XML 恢复后续)

前情提要:https://rainylog.com/post/oracle-pdb-xml-recover/


按照前文所述,可以成功地将 pdb 插回 cdb 中,当我惊叹于仅凭一个 DBMS_PDB.RECOVER 可以恢复时,却不知为后面的坑埋下伏笔…

临时表空间丢失

该 pdb 最初从单实例非 ASM 磁盘管理的数据库中拔出,插入到 RAC 环境,使用了 OMF。

所以该 pdb 的临时表空间和 RAC 另外节点的 undo 表空间都使用 OMF 管理,因而在之前的操作恢复 xml 的过程中,不包含这些表空间,所以恢复时仅包含以下表空间:

  • a_data01.dbf
  • b_data01.dbf
  • sysaux01.dbf
  • system01.dbf
  • undotbs01.dbf

恢复插入一次,随后又拔出过一次,再次插入,可以在 DBA_TABLESPACES 看到如下信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
TABLESPACE_NAME    STATUS
----------------------------------
SYSTEM ONLINE
SYSAUX ONLINE
UNDOTBS1 ONLINE
TEMP OFFLINE
A_DATA ONLINE
A_TEMP OFFLINE
B_DATA ONLINE
B_TEMP OFFLINE
UNDO_2 OFFLINE
UNDO_3 OFFLINE
UNDO_4 ONLINE

之前用户 A 和用户 B 的临时表空间还有默认临时表空间都变为 OFFLINE 状态。

导致应用报错:

ORA-01524: 表空间 ‘A_TEMP’ 脱机,无法在其中分配空间

尝试将之前的临时表空间改为在线状态:

1
2
3
4
5
SQL> ALTER TABLESPACE TEMP ONLINE;
ALTER TABLESPACE TEMP ONLINE
*
ERROR at line 1:
ORA-65153: cannot bring tablespace online

出现报错,在这篇文章最末可以看到解释:

“ORA-65153: cannot bring tablespace online

Cause: An attempt was made to bring online a tablespace that was either missing in the plug XML file or excluded when the pluggable database was created.
Action: Drop and recreate the tablespace to bring it online.”

Reference: http://docs.oracle.com/database/121/ERRMG/e60000.htm

原引用地址现在已经更为:https://docs.oracle.com/en/database/oracle/oracle-database/18/errmg/ORA-60001.html#GUID-9B78A028-D760-4810-9CFC-9013FBD1FCC9

好吧,只能重建临时表空间,并将用户表空间设为新建的临时表空间:

1
2
3
alter database default temporary tablespace temp1;
alter user A temporary tablespace a_temp1;
alter user B temporary tablespace b_temp1;

之后发现可以正常访问和查询了。

UNDO

上面可以看到产生了几个 UNDO 表空间,在 RAC 下,第一节点使用 UNDOTBS_1,第二节点会自动分配一个新的表空间 UNDO_2,这是未拔出前的状态。然后拔了两次恢复了两次,出现了 UNDO_2 和 UNDO_3 的 OFFLINE 状态,所以现在自动分配了一个 ONLINE 的 UNDO_4。

ORA-00600

当该 pdb 插回数据库中,业务应用可以启动成功。但是前台执行某些操作会报 closed Connection。

技术在编译包,对表查询时使用复杂查询语句,会报错误:

ORA-00600: 内部错误代码,参数:[25029], [14], [14], [8], [], [], [], [], [], [], [], []

猜想是否由于之前的临时表空间为离线状态,会影响到现在的查询。

尝试将之前 OFFLINE 的临时表空间 DROP 掉。

1
2
3
4
5
6
SQL> drop tablespace temp including contents and datafiles;
drop tablespace temp including contents and datafiles
*
ERROR at line 1:
ORA-00600: internal error code, arguments: [krtlft-01], [5], [], [], [], [],
[], [], [], [], [], []

查询资料,找不到类似错误,看到了类似的一篇文章:http://yangtingkun.net/?p=654

按照文中方法,查询数据字典是否出现了不一致状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SQL> SELECT ts#, COUNT(*) FROM seg$ GROUP BY ts#;

TS# COUNT(*)
---------- ----------
1 2353
6 1460
2 17
4 7063
8 12
0 851
10 11
9 10

8 rows selected.

SQL> SELECT ts#, COUNT(*) FROM tab$ GROUP BY ts#;

TS# COUNT(*)
---------- ----------
1 1348
6 690
4 2749
0 1260

好吧,一看就是要炸的节奏。

猜测之前在库里记录的表空间信息的数据文件路径等已经丢失,正常的话,查询 sys.V_$DATAFILE 和 sys.DBA_TABLESPACES 记录条数应该保持一致,在这里显然不一致。

仍旧无法定位具体问题,但是目前数据还在,着眼于恢复数据库底层的数据字典和记录无疑有很大困难。既然数据记录都在,如果导出数据文件重建新的 PDB 导入用户数据,就可以规避操作数据库底层而引发风险。

尝试导出

尝试使用 expdp 导出数据:

1
2
3
4
5
6
7
8
Export: Release 12.2.0.1.0 - Production on Wed Mar 7 14:06:44 2018

Copyright (c) 1982, 2017, Oracle and/or its affiliates. All rights reserved.

Connected to: Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

UDE-22303: operation generated ORACLE error 22303
OCI-22303: type "SYS"."KU$_STATUS1220" not found

网上查询资料获得如下解释:

It looks like you can’t use DBMS_OUTPUT.

还有此篇文章的解决方法:http://m.blog.itpub.net/26706/viewspace-366439/

奇怪的是在单实例下可以进行导出操作。

所以暂不追究原因,使用单实例导出,不过此次导出三线程很慢。

导出到最后报错:

1
2
3
4
5
6
7
8
9
10
tail -f nohup.out 
ORA-31623: a job is not attached to this session via the specified handle
ORA-06512: at "SYS.DBMS_DATAPUMP", line 4750
ORA-06512: at "SYS.KUPV$FT_INT", line 1872
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 79
ORA-06512: at "SYS.KUPV$FT_INT", line 1805
ORA-06512: at "SYS.DBMS_DATAPUMP", line 2266
ORA-06512: at "SYS.DBMS_DATAPUMP", line 4498
ORA-06512: at "SYS.DBMS_DATAPUMP", line 6104
ORA-06512: at line 1

出现此问题的原因可能是多样的,参见文章:

由一个问题引出导出数据的报错问题,现在去一个个排查无疑时间成本很高

PL/SQL

后来想到在本地用 PL/SQL 可以查询数据,那么可以使用 PL/SQL 的导出功能。

Tools -> Export User Objects…

导出的表结构达 60M,费时两个小时。若包含数据,那么导出速度可想而知。

EXP

这时经同事提示 PL/SQL 的导出可能调用 EXP,EXP 是纯客户端程序。因而在服务器上尝试使用 EXP 进行导出。

导出过程中报错很多:

EXP-00091 Exporting questionable statistics

这是数据库字符集和本地电脑字符集不一致导致的,不过并不影响数据的导入导出。

导入成功

经过 exp 导出后,导入到新的 PDB 中,应用可以正常启动和使用。

在恢复该 PDB 的过程中,可以看到网上很多专业的文章试图从数据库底层出发去进行数据恢复,不过这次的问题在于数据库能够正常使用,数据可以查询到。那么就不要轻易使用网上的方法进行底层修复,有可能造成无法挽回的后果。有时往往简单的方法可以奏效,例如之前有一次出现数据库逻辑坏块时,网上的方法是一点一点的进行数据块的恢复。但是发现,使用导入导出数据的方法无需理会逻辑坏块的存在,直接导入新库即可修复。

在时间成本允许的条件下,尽可能使用稳妥和简单的思路,往往能够获得惊喜的结果。

后记

该错误 PDB 依旧躺在 CDB 内,抽时间可以对此进行研究,看能否用其它方式进行恢复,也是对数据库底层进行了解的良机。如果找到修复方法也会重新写一篇文章来讲讲思路。

针对 ORA-00600,参考了许多文章,看到的相关文章列表如下,供以后查阅:

-EOF-

本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明出处! © 雨落
  1. 1. 临时表空间丢失
    1. 1.1. UNDO
  2. 2. ORA-00600
  3. 3. 尝试导出
    1. 3.1. PL/SQL
    2. 3.2. EXP
  4. 4. 导入成功
  5. 5. 后记