因硬盘空间不够误删oracle redo日志文件导致数据库崩溃的抢救日志

513 阅读10分钟

因硬盘空间不够误删redo日志文件的抢救日志

事出有因

早上同事反馈数据库无法访问,第一时间就想到了硬盘空间不足,因为数据库的机器资源一直不够,所以都是删除多余的文件,对没错,由于DBA知识严重不足,对oracle的基本结构都不清楚,傻乎乎的把redo日志删除了…………

刚开始抛缺少redo的错误,后来根据百度的结果操作了几次,现在提示。

SQL> alter database open resetlogs;
alter database open resetlogs
*1 行出现错误:
ORA-01194: 文件 1 需要更多的恢复来保持一致性
ORA-01110:数据文件:1:'xxxxx\APP\ORADATA\ORCL\SYSTEM01.DBF'

抓紧补救

这个数据库里甚至还有生产数据,没有意识到redo日志删除的严重性,就觉着是一个无关紧要的文件,跟着提醒百度解决问题,后来才意识到问题的严重性!

开始解决问题

查找资料

咨询了几个dba,也大致的说了他们的解决方法,从他们的解决方法中学习了两个关键词:DUL和强制启动,DUL搜索了一下,挺复杂没看明白,就从强制启动的思路开始,因为我是在运行中删除的redo日志文件,会将当时在内存中的数据全部丢失,并且强制启动会丢失字典,会造成数据的不一致性,比如表和数据的Index不一致等。

结合几篇文章,大致的处理思路是:

  1. 增加隐含参数,强制启动
  2. 导出数据
  3. 重建数据库

这只是大致的思路,里面有很多具体的细节要实现,作为oracle小白,也搞不太明白,一点点来吧。

由于对Oracle的了解操作水平比较差,同事把整个虚拟机进行快照处理,如果没弄好,可以随时还原再弄,如果备份不方便也可以在docker中搭建一个oracle环境,然后再把redo删除,模拟故障,先在docker中模拟测试,没问题再真正操作。

什么是强制启动,强制启动之后怎么做 首先来了解一下强制启动的概念:

当日志文件有问题时可以使用隐含参数_allow_resetlogs_corruption强制启动数据库.设置此参数之后,在数据库Open过程中,Oracle会跳过某些一致性检查,从而使数据库可能跳过不一致状态,Open打开。

首先修改pfile文件,pfile大致是全局的参数文件,可以通过show parameter pfile命令来查看当前的文件存储位置,在修改之前请别忘记备份

如果没有创建过pfile文件,通过show parameter pfile命令查询后,查询出来的是spfile文件,spfile文件大致就是二进制文件,我们没办法修改,所以要再创建一个pfile文件。

SQL> show parameter pfile

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
spfile                               string      C:\ORACLE\APP\PRODUCT\19.3\DBH
                                                 OME_1\DATABASE\SPFILEORCL.ORA`

创建pfile文件(也可不指定目录)

create pfile=’c:/pfile1108.ora‘ from spfile;

创建之后在pfile1108.ora中增加四个参数

_allow_resetlogs_corruption=true
_offline_rollback_segments=true
event=82329618 trace name context forever, level 3
_corrupted_rollback_segments=(_SYSSMU2$,_SYSSMU3$,_SYSSMU4$,_SYSSMU5$,_SYSSMU6$,_SYSSMU7$,_SYSSMU8$,_SYSSMU9$,_SYSSMU10$,_SYSSMU1$,_SYSSMU11$,_SYSSMU12$,_SYSSMU13$,_SYSSMU14$,_SYSSMU15$,_SYSSMU16$,_SYSSMU17$,_SYSSMU18$,_SYSSMU19$,_SYSSMU20$)
  • 第一个参数:_allow_resetlogs_corruption=true 缺少归档日志增加
  • 第二个参数:_offline_rollback_segments=true 可以解决回滚问题
  • 第三个参数:event=82329618 trace name context forever, level 3 只搞明白了第一个参数82329618的意思,就是数据库SNA值
  • 第四个参数:破坏回滚段

查询SCN值的方法

SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
          82329618

查询出来后记得替换第三个参数的SCN值。

关闭数据库

shutdown immediate;

ORA-01109: 数据库未打开
已经卸载数据库。
ORACLE 例程已经关闭。

启动数据库

startup pfile='c:/pfile1108.ora';

ORACLE 例程已经启动。
Total System Global Area 2583687184 bytes
Fixed Size                  9031696 bytes
Variable Size            1426063360 bytes
Database Buffers         1140850688 bytes
Redo Buffers                7741440 bytes
数据库装载完毕。
数据库打开完成。

后续启动,直接用startup即可直接启动。

我的就是这么简单完成的,打开的数据库依然正常使用,数据也没有发生什么变化,不过会定时挂掉。要尽快把数据备份出来! 尝试了N种方法才解决这个问题,使用alter database open resetlogs; 一直抛异常,使用上述方法顺利启动起来。

启动起来之后无法导出和定时挂掉

虽然可以启动起来,但是启动起来之后无法导出,也会定时关闭,找到C:\Oracle\app\diag\rdbms\orcl\orcl\trace\alter_orcl.log这个日志,发现有:

Incident details in: C:\ORACLE\APP\diag\rdbms\orcl\orcl\incident\incdir_205357\orcl_m002_6196_i205357.trc
2022-11-09T12:00:49.265169+08:00
opidrv aborting process M002 ospid (6196) as a result of ORA-603
2022-11-09T12:00:52.280900+08:00
Flush retried for xcb 0x96de8570, pmd 0x95a1c138
Doing block recovery for file 4 block 2250
Errors in file C:\ORACLE\APP\diag\rdbms\orcl\orcl\trace\orcl_clmn_6392.trc  (incident=205163):
ORA-00600: 内部错误代码, 参数: [4194], [2], [2], [], [], [], [], [], [], [], [], []
Use ADRCI or Support Workbench to package the incident.
See Note 411.1 at My Oracle Support for error and packaging details.
2022-11-09T12:00:52.421527+08:00
Errors in file C:\ORACLE\APP\diag\rdbms\orcl\orcl\trace\orcl_clmn_6392.trc:
ORA-00600: 内部错误代码, 参数: [4194], [2], [2], [], [], [], [], [], [], [], [], []
Errors in file C:\ORACLE\APP\diag\rdbms\orcl\orcl\trace\orcl_clmn_6392.trc  (incident=205164):
ORA-501 [] [] [] [] [] [] [] [] [] [] [] []
Incident details in: C:\ORACLE\APP\diag\rdbms\orcl\orcl\incident\incdir_205164\orcl_clmn_6392_i205164.trc
2022-11-09T12:00:53.921573+08:00

ORA-00600的错误,但是根据之前的提醒,我已经增加了_corrupted_rollback_segments 参数启动,但是还是不行,又仔细查找了一下资料,发现是因为存在回滚段导致的,需要将回滚段破坏,也没有正确理解_corrupted_rollback_segments参数的意思。

什么是回滚段呢,摘抄一段前辈的解释:

回滚段是在事务中间过程中,将修改前的状态记录下来,记录的过程中加上类似时间戳的scn。它的主要作用有两个:

1.当事务出现错误回滚的时候,原始数据可以从回滚段中找回。

2.实现读一致性。当读操作读取到某一行,发现这行数据已经被修改,就会根据读取时刻的scn去回滚段中找之前的数据。

回滚段还有一个重要作用就是误删数据恢复。

我们接着操作,先把服务启动起来查询回滚段。

SQL> select segment_name, tablespace_name, status from dba_rollback_segs;

SEGMENT_NAME                   TABLESPACE_NAME                STATUS
------------------------------ ------------------------------ ----------------
SYSTEM                         SYSTEM                         ONLINE
_SYSSMU1_3741171459$           UNDOTBS1                       ONLINE
_SYSSMU2_1557575246$           UNDOTBS1                       ONLINE
_SYSSMU3_3193270435$           UNDOTBS1                       ONLINE
_SYSSMU4_2372004640$           UNDOTBS1                       ONLINE
_SYSSMU5_553218552$            UNDOTBS1                       ONLINE
_SYSSMU6_3809612316$           UNDOTBS1                       ONLINE
_SYSSMU7_3306078869$           UNDOTBS1                       ONLINE
_SYSSMU8_115127830$            UNDOTBS1                       ONLINE
_SYSSMU9_4165470211$           UNDOTBS1                       ONLINE
_SYSSMU10_3563521556$          UNDOTBS1                       ONLINE

SEGMENT_NAME                   TABLESPACE_NAME                STATUS
------------------------------ ------------------------------ ----------------
_SYSSMU11_135927606$           UNDOTBS1                       ONLINE

重构一下参数,把SEGMENT_NAME用逗号分隔(英文逗号),拼接,最后用括号包裹,如下:

_corrupted_rollback_segments=(_SYSSMU1_3741171459$,_SYSSMU2_1557575246$,_SYSSMU3_3193270435$,_SYSSMU4_2372004640$,_SYSSMU5_553218552$,_SYSSMU6_3809612316$,_SYSSMU7_3306078869$,_SYSSMU8_115127830$,_SYSSMU9_4165470211$,_SYSSMU10_3563521556$,_SYSSMU11_135927606$)

pfile1108.ora配置文件中替换_corrupted_rollback_segments参数。

在修改参数重启之前我们要将undo表空间的undo_management参数的auto改成manual,很多文章都提到要重建undo表空间,应该是丢失redo会损坏undo表空间的运行,至于undo表空间的作用是:

1、提供读一致性

2、为事务提供回滚

3、提供闪回操作

所以我们要在破坏回滚段之前先将undo_management参数的auto改成manual,该参数决定UNDO 空间的管理是自动还是手动

#在配置文件的_corrupted_rollback_segments前面追加
undo_management='manual'

重新启动数据查看回滚段

SQL> select segment_name, tablespace_name, status from dba_rollback_segs;

SEGMENT_NAME                   TABLESPACE_NAME                STATUS
------------------------------ ------------------------------ ----------------
SYSTEM                         SYSTEM                         ONLINE
_SYSSMU1_3741171459$           UNDOTBS1                       NEEDS RECOVERY
_SYSSMU2_1557575246$           UNDOTBS1                       NEEDS RECOVERY
_SYSSMU3_3193270435$           UNDOTBS1                       NEEDS RECOVERY
_SYSSMU4_2372004640$           UNDOTBS1                       NEEDS RECOVERY
_SYSSMU5_553218552$            UNDOTBS1                       NEEDS RECOVERY
_SYSSMU6_3809612316$           UNDOTBS1                       NEEDS RECOVERY
_SYSSMU7_3306078869$           UNDOTBS1                       NEEDS RECOVERY
_SYSSMU8_115127830$            UNDOTBS1                       NEEDS RECOVERY
_SYSSMU9_4165470211$           UNDOTBS1                       NEEDS RECOVERY
_SYSSMU10_3563521556$          UNDOTBS1                       NEEDS RECOVERY

SEGMENT_NAME                   TABLESPACE_NAME                STATUS
------------------------------ ------------------------------ ----------------
_SYSSMU11_135927606$           UNDOTBS1                       NEEDS RECOVERY
_SYSSMU12_3384371406$          UNDOTBS1                       OFFLINE
_SYSSMU13_2038117684$          UNDOTBS1                       OFFLINE

已选择 14 行。

发现STATUS的状态都变了,不是原来的ONLINE,现在可以建立新的undo表空间了。

SQL> create undo tablespace undotbs2 datafile 'C:\Oracle\app\oradata\UNDOTBS02.DBF' size 100m autoextend on next 100m maxsize unlimited;

表空间已创建。

在配置文件上把undo_management修改成auto

undo_management='auto'

在配置文件上再增加一个新的配置

undo_tablespace='undotbs2'

重新启动数据库

SQL> startup pfile='C:\Oracle\app\oradata\pfile1108.pra'
ORACLE 例程已经启动。

Total System Global Area 2583687184 bytes
Fixed Size                  9031696 bytes
Variable Size            1426063360 bytes
Database Buffers         1140850688 bytes
Redo Buffers                7741440 bytes
数据库装载完毕。
数据库已经打开。

查看undo配置修改是否生效

SQL> show parameter undo

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
temp_undo_enabled                    boolean     FALSE
undo_management                      string      AUTO
undo_retention                       integer     900
undo_tablespace                      string      UNDOTBS2

观察undo_management和undo_tablespace的VALUE值都修改过来了。

之后不操作数据库,再观察是否还异常停止。

经过一段时间的观察alert_orcl.ora没有抛相关异常了

重建数据库

最后全部修复后,需要重建一个数据库,使用expdp把数据从旧数据库中导出再导入到新数据库中。

导出数据

1、首先先创建一个目录,已经有了,就不用创建了
sqlplus /nolog
conn / as sysdba
create directory dump_dir as 'C:\dump';
#然后在cmd中执行
>expdp 账号/密码@127.0.0.1:1521/orcl directory=dump_dir dumpfile='xxx.dmp' schemas=用户名

导出很顺利,把生成的文件放到目标服务器,准备导入。

导入数据

sqlplus /nolog
conn / as sysdba
create directory dump_dir as 'c:\temp';
create tablespace xxxxxx datafile '数据文件路径' size xxxG autoextend on ;
exit
cmd模式下
impdp system/oracle directory=dump_dir dumpfile=xxxxxx.dmp schemas='用户名'

导入报错

ORA-39083: 对象类型 TABLE:"XXX"."XXX" 创建失败, 出现错误:
ORA-00376: 此时无法读取文件 17
ORA-01111: 数据文件 17 名称未知 - 请重命名以更正文件
ORA-01110: 数据文件 17:xxxxxx

2022年11月09日19:10:42 导出日志没有错误,导入不行,前面这么多问题都克服解决了,在最后的一步,实在找不到资料,准备放弃。

2022年11月09日19:53:00 修整一下继续,程序员怎么能轻言放弃。

分析报错1

首先看下数据库版本

C:\Users\Administrator>sqlplus -v
SQL*Plus: Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

导入和导出的数据库版本都没有问题。

再看下导出的数据库是否还有异常

2022-11-09T19:54:05.202174+08:00
Errors in file C:\ORACLE\APP\diag\rdbms\orcl\orcl\trace\orcl_mz00_8624.trc:
ORA-01110: 数据文件 13: 'C:\ORACLE\APP\PRODUCT\19.3\DBHOME_1\DATABASE\xx.DBF'
ORA-01565: 标识文件 'C:\ORACLE\APP\PRODUCT\19.3\DBHOME_1\DATABASE\xx.DBF' 时出错
ORA-27041: 无法打开文件
OSD-04002: 无法打开文件
O/S-Error: (OS 2) 系统找不到指定的文件。

日志文件还有抛找不到.dbf的错误,不管怎么样,先把这个错误消除了吧。

这个文件我已经物理删除过了,所以用sql直接把这个表空间删除。

SQL> drop tablespace 表空间名称 including contents cascade constraints;

drop tablespace YUSUAN including contents cascade constraints
*1 行出现错误:
ORA-00604: 递归 SQL 级别 1 出现错误
ORA-02429: 无法删除用于强制唯一/主键的索引

删除不掉,有主键冲突。

SQL> select segment_name,partition_name,tablespace_name from   dba_extents    where tablespace_name=upper('xxx');

未选定行

在dba_extents中也查询不到。


SQL> select 'alter table '||owner||'.'||table_name||' drop constraint '||constraint_name||' ;'
  2  from dba_constraints
  3  where constraint_type in ('U', 'P')
  4  and (index_owner, index_name) in
  5  (select owner, segment_name
  6  from dba_segments
  7  where tablespace_name = 'YUSUAN');

未选定行

换一种,依然查不到。

SQL> drop user XXX cascade;

用户已删除。

SQL> drop tablespace XXX including contents cascade constraints;

表空间已删除。

依然不放弃,换一种方法,删除成功!

再看日志文件

没有错误了,清空所有日志,再导出试试,看看有没有错误。

已成功加载/卸载了主表 "XXX"."SYS_EXPORT_SCHEMA_17" 
******************************************************************************
XXX.SYS_EXPORT_SCHEMA_17 的转储文件集为:
  C:\TEMP\XXX.DMP
作业 "XXX"."SYS_EXPORT_SCHEMA_17" 已于 星期三 119 20:27:27 2022 elapsed 0 00:01:28 成功完成

导出还是成功的

DM00 started with pid=94, OS id=8564, job XXX.SYS_EXPORT_SCHEMA_17
2022-11-09T20:25:59.695289+08:00

DW00 started with pid=97, OS id=9984, wid=1, job XXX.SYS_EXPORT_SCHEMA_17
2022-11-09T20:26:15.226481+08:00

XDB initialized.

日志也没有什么错误,再导入试试。

已经完成,但是有 854 个错误。

还是跟没排错之前一样,看来不是这个问题,调整一下心态继续。

分析报错2

查资料记录一个思路,可以在当前服务器导出再导入试试,因为我都是把dmp放到另外一个服务器的数据库中导入的,暂时不试,主要是当前服务器硬盘没有资源。

根据错误提醒,怀疑是这个数据库有表空间啥的冲突了,决定到docker里试试。

ORA-39083: Object type TABLE:"OPENDATA_JS_MAIN"."PRO_BATCHIMPORT_STATUS" failed to create with error:
ORA-00439: feature not enabled: Partitioning

在docker里导入之后的错误,跟之前不一样了,查询了一下应该是分区未打开(我的表用了分区)。

再次分析一下,是镜像的问题,如果使用oracle分区要用企业镜像,换镜像再来一遍。

在镜像里修改字符集、创建表空间、创建用户、正常导入,成功!,所以说还是我上个数据库也存在问题,采择可能是表空间重复之类的,具体不细究了。

最后

最终耗时三天完成了这个问题的修复,期间解决N个问题,数据库问题、linux问题、docker问题等等,查找了大量资料,心理憔悴,一度怀疑自己能不能搞定,坚持下来了,最终解决这个问题,对于专业的DBA来说,可能只是小意思,但是对于一个水平不够的后端来说,着实花了功夫,最后再总结一下。

  1. 数据库最初没有估算好数据库所需资源,扩容不及时,缝缝补补最终才造成这个问题。
  2. 缺少DBA,尤其是我这样dba知识不够瞎操作才造成的最终问题
  3. 数据库缺少日常巡检,后续要增加脚本自动巡检
  4. 对整个数据库进行定时增量备份

感谢书写这些文章的前辈!!!: