这三件事在运维中经常连在一起出现:维护前要按正确顺序停库停集群,做热备份前要确认归档已开启,而归档或表空间操作稍有不慎,就可能遇到数据文件路径错误导致的 ORA-01157。本文按“启停 → 归档 → 故障修复”的顺序整理,命令均取自原文的实操记录。
适用范围:Oracle 19c,RAC 部分同样适用于 11g/12c 的 CRS 管理方式;ORA-01157 的案例原文发生在 11g RAC 环境,处理思路对 19c 一致,但路径和磁盘组名要按实际替换。
一、RAC 启停顺序
原则只有一句:启动先集群后数据库,关闭先数据库后集群。顺序反了,数据库实例会先于集群资源下线,轻则报资源状态异常,重则留下未完成的实例恢复。
关闭
先以 grid 用户确认当前状态,再停数据库:
-- 查看数据库服务状态
crsctl stat res -t
-- 停数据库
srvctl stop database -d 服务名
-d 后面是数据库名,不是实例名。RAC 下这条命令会停掉所有节点上的实例,不需要逐节点执行。
数据库完全停止后,再用 root 停集群,两个节点都要操作:
-- 停集群(两个节点都操作)
/oracle/app/19.3.0/grid/bin/crsctl stop crs
两个节点之间要留出时间差。节点一停完、确认 crsctl check crs 已离线,再停节点二;同时停两个节点容易让集群在关闭过程中互相等待。停集群会连带停掉 ASM、监听和所有由 CRS 管理的资源,所以必须先确认数据库已经停干净。
启动
先起集群,仍然是两个节点都执行:
-- 启动集群(两个节点都操作)
/oracle/app/19.3.0/grid/bin/crsctl start crs
节点一启动完成后再启动节点二。集群起来后,用 grid 用户检查:
-- 检查集群状态
crsctl check crs
CRS-4638: Oracle High Availability Services is online
CRS-4537: Cluster Ready Services is online
CRS-4529: Cluster Synchronization Services is online
CRS-4533: Event Manager is online
四条都 online 才算集群正常。接着确认 ASM 和数据库进程:
-- 确认服务
ps -ef | grep smon
-- 查看数据库状态
crsctl status res -t
......
ora.testcdb.db
1 OFFLINE OFFLINE Instance Shutdown,STABLE
2 OFFLINE OFFLINE Instance Shutdown,STABLE
此时实例处于 Instance Shutdown,STABLE,说明集群没有自动拉起数据库,这是正常的。最后启动数据库:
-- 启动数据库
cd /oracle/app/19.3.0/grid_1/bin
srvctl start database -d 服务名
原文这里切换到 grid_1/bin 执行 srvctl,说明环境中存在多个 Grid Home 或 PATH 未包含 srvctl。如果直接执行 srvctl 报“command not found”,用绝对路径,不要以为是集群坏了。
启动后再查一次 crsctl status res -t,确认所有实例为 ONLINE、服务状态为 STABLE。
常见错误
- 只停了一个节点的实例就停集群:另一个节点上的实例会被强制终止,需要实例恢复。
- 先停集群再停数据库:
srvctl stop database失去 CRS 支撑,可能挂起。 - 启动时只起了一个节点的 CRS 就起库:另一个节点实例起不来,或者资源状态长期
INTERMEDIATE。 - 用
sqlplus shutdown代替srvctl stop database:单节点可以,RAC 下容易只停本节点,另一节点仍在运行。
启停时的两个易错点
只维护一个节点。 如果只是重启某个实例,不要停整个数据库,也不要用 shutdown immediate 在单节点操作后再手动拉起,容易和 CRS 的资源管理打架。正确做法是用 srvctl 针对实例操作,并在操作后用 crsctl status res -t 确认另一个节点未受影响。停机维护前先确认没有业务连接落在该实例上,必要时先 srvctl stop service 把服务摘走。
启停后没有验证监听。 集群起来不代表监听已经注册好。数据库启动后,用 lsnrctl status 确认实例已注册到监听,再用 tnsping 或实际连接验证。RAC 下还要确认 SCAN 监听在所有节点都正常,否则应用可能连到未注册的节点。
二、开启归档模式
归档模式是热备份的前提。Oracle 默认是非归档模式,开启操作必须在数据库 MOUNT 状态执行,不能在 OPEN 状态直接切换。
前置检查与备份
先确认当前状态:
archive log list;
再备份一份 pfile,便于参数改错时回退:
create pfile='/home/oracle/pfile1216.ora' from spfile;
这一步成本很低,但很关键。归档相关参数(db_recovery_file_dest、db_recovery_file_dest_size、log_archive_dest_1)一旦写错,数据库可能起不来,有 pfile 至少能定位原始参数。
同时确认归档空间足够。开启归档后,如果 db_recovery_file_dest_size 太小,很快会因归档写满导致数据库挂起。
操作步骤
- 关闭数据库。RAC 环境两个节点都要停:
shutdown immediate;
- 在节点一启动到 mount:
startup mount;
- 切换归档并打开:
alter database archivelog;
alter database open; --启动数据库,RAC的话需要双节点执行
archive log list;
alter database archivelog 只在节点一执行;alter database open 在 RAC 下需要两个节点都执行,或者直接用 srvctl start database -d 服务名 统一拉起。
- 调整归档空间:
show parameter db_recovery_file_dest_size;
-- 修改归档空间大小
alter system set db_recovery_file_dest_size=100G;
100G 是示例值,按实际归档保留策略和磁盘容量设置。这个参数可以在线修改,不需要重启。
- 确认归档目录:
show parameter recovery_file_dest;
-- 修改归档目录
# 单机路径
alter system set log_archive_dest_1='location=/oracle/app/db/archivelog' scope=both;
# RAC环境路径
alter system set db_recovery_file_dest='+ARCHDG';
单机用文件系统目录时改 log_archive_dest_1;RAC 使用 ASM 时改 db_recovery_file_dest 指向归档磁盘组。两种写法不要混用:同时设置 log_archive_dest_1 和 db_recovery_file_dest,归档可能落到非预期位置。
- 再次确认:
archive log list;
输出中的 Database log mode 应为 Archive Mode,Automatic archival 应为 Enabled。
归档空间与保留策略
开启归档只是第一步,能不能长期稳定运行取决于空间。查当前使用情况:
select name,space_limit/1024/1024/1024 limit_g,
space_used/1024/1024/1024 used_g,
space_reclaimable/1024/1024/1024 reclaim_g,
number_of_files
from v$recovery_file_dest;
space_reclaimable 是已经被 RMAN 标记为可删除、但尚未清理的空间。它长期很大,说明备份清理策略没有生效,需要检查 RMAN 的保留策略和归档删除作业,而不是一味扩容。
查归档目标的状态和错误:
select dest_id,dest_name,status,error,binding
from v$archive_dest
where dest_id<=10;
status 为 ERROR 时,error 列会给出具体原因,常见的是空间满、路径不可写、ASM 磁盘组未挂载。归档写不进去时数据库会挂起(ARCHIVELOG 模式下 redo 无法覆盖),所以这个查询应该纳入日常监控。
如果使用 FRA(db_recovery_file_dest),还要确认 log_archive_dest_1 没有被同时设置成文件系统路径。两者同时生效时,归档可能写到非预期位置,FRA 的空间统计也会失真。
三、关闭归档模式
关闭归档的步骤与开启对称,同样要求 MOUNT 状态:
archive log list;
shutdown immediate;
startup mount;
alter database noarchivelog;
alter database open; --启动数据库,rac的话需要双节点执行
archive log list;
关闭归档前必须想清楚后果,原文列出的几点都成立:
- 数据丢失无法回退:没有归档,只能恢复到上一次备份点。
- 只能做逻辑备份,系统异常时仍存在数据丢失。
- 逻辑备份需要额外的本地空间和长期保留策略,备份时间长,且影响性能。
- 数据库坏块可能导致系统不可用,逻辑备份无法修复坏块,只能重建。
生产库不建议关闭归档。如果只是为了省空间,优先调整归档保留策略或扩容归档盘,而不是切到非归档模式。
四、ORA-01157:数据文件落在本地
现象与原因
在 RAC 环境创建表空间时,如果漏写 +DATADG,数据文件会落到本地文件系统,例如 /oracle/app/db/systemnew3.dg。本节点可能还能访问,另一个节点完全看不到这个路径,启动或访问时报:
ORA-01157: cannot identify/lock datafile
原文只记录了 01157 这一行。实际环境中通常还会跟一条 ORA-01110 指出具体文件,以告警日志和 v$datafile 的输出为准。
根因不是数据文件损坏,而是路径只在一个节点存在。所以修复方向是让所有节点通过 ASM 访问同一个文件,而不是去“恢复”文件。
三种方式按侵入性从低到高排列:ASM 拷贝改名 → RMAN switch → 重建表空间。优先用前两种,重建表空间是最后手段。
先定位是哪个文件
ORA-01157 的报错文本里通常只有文件号,没有路径。先查清楚缺的是哪个文件:
select file#,status,error,name from v$datafile order by file#;
status 为 OFFLINE 且 error 列显示 CANNOT IDENTIFY 的,就是问题文件。再用 v$recover_file 确认:
select file#,online_status,error,change#,time from v$recover_file;
如果数据库还能启动到 mount,这两个视图足够定位。如果实例已经起不来,只能看告警日志里 ORA-01157 后面的文件名。
定位之后先判断文件是否真实存在、是否可读:
ls -l /oracle/app/db/systemnew3.dg
文件存在但只有本节点可见,是本文讨论的路径问题;文件不存在或大小为 0,说明问题更严重,需要从备份恢复,不能靠 rename 解决。
方式一:asmcmd 拷贝并 rename
适用于数据文件内容完好、只是位置不对的情况。
- 在正常节点关闭数据库:
SQL> shutdown immediate;
- 用 asmcmd 把本地文件复制进 ASM:
ASMCMD> cp /oracle/app/db/systemnew3.dg .
copying /oracle/app/db/systemnew3.dg -> +DATADG/TESTCDB/DATAFILE/systemnew3.dg
ASMCMD> pwd
+DATADG/TESTCDB/DATAFILE
ASMCMD>
cp 的目标写成 .,表示复制到当前目录。执行前先 cd 到目标数据文件目录,复制完成后记下 ASM 自动生成的文件名。
- 启动到 mount:
SQL> startup mount
- 修改控制文件中的路径:
SQL> alter database rename file '/oracle/app/db/systemnew3.dg' to '+DATADG/TESTCDB/DATAFILE/systemnew3.dg';
Database altered.
- 打开数据库:
SQL> alter database open;
- 重启验证,两个节点都要做:
shutdown immediate;
startup;
节点二同样执行 shutdown immediate 和 startup。只在节点一验证通过不算完成,必须确认节点二也能正常打开。
注意事项:rename 只改控制文件记录,不会搬文件;必须先 cp 成功,再执行 rename。顺序反了,数据库会找不到文件。复制期间数据库应处于关闭或至少该数据文件离线状态,避免文件头不一致。
变体:停集群后拷贝(原文方式二)
适用于需要确保所有节点都不持有该文件的场景。
- 关闭整个集群,在节点一用 grid 登录 asmcmd 复制:
ASMCMD > cp /app/oracle/11.2.0/db_1/dbs/DATADG +DATADG/NCM/DATAFILE/SYSTEM01.dbf (DATADG是错误创建的数据文件)
copying /app/oracle/11.2.0/db_1/dbs/DATADG - > +DATADG/NCM/DATAFILE
原文这条命令的目标路径写的是 SYSTEM01.dbf,源文件却叫 DATADG,且后面的 rename 又指向 +DATADG/NCMAIL/DATAFILE/SYSTEM01.dbf。这三处名称不一致,实际执行时必须统一成真实文件名和真实目录,否则会复制出错误文件或 rename 失败。此处保留原文,供对照。
- 启动数据库到 mount:
srvctl start database -d NCM -o mount
- 修改路径:
alter database rename file '/app/oracle/11.2.0/db_1/dbs/DATADG' to '+DATADG/NCMAIL/DATAFILE/SYSTEM01.dbf';
- 关闭集群并正常启动,确认两个节点都能打开。
这种方式停机时间更长,但能避免“节点二仍持有本地文件句柄”的干扰。如果方式一在节点二反复报错,可以改用这种方式。
方式二:RMAN backup as copy + switch
适用于希望由 RMAN 管理文件副本、并保留备份记录的场景。核心是三步:做成映像副本、set newname、switch。
- 做数据文件映像副本:
RMAN> run
2> { allocate channel c1 type disk;
3> backup as copy datafile 7 format '+DATA'; }
using target database control file instead of recovery catalog
allocated channel: c1
channel c1: SID=71 instance=ora11211 device type=DISK
Starting backup at 27-AUG-22
channel c1: starting datafile copy
input datafile file number=00007 name=/u01/app/oracle/11.2.0.4/dbs/1.test
output file name=+DATA/ora112/datafile/system.269.1113783961 tag=TAG20220827T002601 RECID=3 STAMP=1113783961
channel c1: datafile copy complete, elapsed time: 00:00:01
Finished backup at 27-AUG-22
released channel: c1
记下输出中的 output file name,下一步要用。文件号 7 是示例,按实际 file_id 替换。
- 设置新文件名:
RMAN> run { set newname for datafile 7 to '+DATA/ora112/datafile/system.269.1113783961';}
executing command: SET NEWNAME
RMAN>
- 切换控制文件记录到副本:
RMAN> switch datafile 7 to copy;
datafile 7 switched to datafile copy "+DATA/ora112/datafile/system.269.1113783961"
switch 之后,控制文件指向副本,原本地文件不再被引用。确认无误后再删除本地文件,不要提前删。
- 确认路径与容量:
set linesize 150;
col tablespace_name format a50;
select a.tablespace_name,a.bytes/1024/1024 "Sum MB",(a.bytes-b.bytes)/1024/1024 "used MB",b.bytes/1024/1024 "free MB",round(((a.bytes-b.bytes)/a.bytes)*100,2) "percent_used"
from (select tablespace_name,sum(bytes) bytes from dba_data_files group by tablespace_name) a,
(select tablespace_name,sum(bytes) bytes,max(bytes) largest from dba_free_space group by tablespace_name) b where a.tablespace_name=b.tablespace_name
order by ((a.bytes-b.bytes)/a.bytes) desc ;
set linesize 300
col tablespace_name for a30
col file_name for a80
col autoextensible for a5
select file_id,tablespace_name,file_name,bytes/1024/1024 MB,autoextensible from dba_data_files order by 1;
原文这两条查询里 groupby、orderby 写成了连写,且 orderby1 缺空格,直接执行会报错;上面按正确语法补了空格,其余字段和别名保持原样。查完确认数据文件路径已经是 ASM,再决定是否需要 resize。
如果新位置所在磁盘组空间紧张,再考虑 resize:
alter database datafile file_id resize **G;
file_id 和 **G 都要替换成实际值;缩小数据文件有下限(不能小于已用块),执行前先确认 dba_free_space。
方式三:重建表空间(最后手段)
当数据文件已经损坏、本地副本不可读,或者表空间里的数据可以从其他来源重建时,才走这条路。原文没有展开具体命令,这里只给顺序,不提供可直接执行的脚本:
- 确认表空间内有哪些对象、能否从其他库或历史备份补齐。
- 用数据泵或 CTAS 把还能读出的数据导出到临时位置。
- 删除原表空间(
drop tablespace ... including contents and datafiles),注意这会删除文件,执行前必须确认导出完整。 - 用
create tablespace在 ASM 上重建,数据文件路径写成+DATADG。 - 导入数据,重建索引、约束、权限和同义词。
- 校验行数、索引状态和业务功能。
这条路停机时间最长,而且依赖备份或外部数据源。能通过 rename 或 switch 解决的,不要重建表空间。
方式选择
| 场景 | 推荐方式 |
|---|---|
| 文件完好、只是路径错,停机窗口短 | 方式一:asmcmd cp + rename |
| 节点二反复报文件被占用 | 方式一的变体:停集群后拷贝 |
| 希望保留 RMAN 副本记录、便于后续恢复 | 方式二:backup as copy + switch |
| 文件已损坏、无法读取,或数据可从别处重建 | 方式三:重建表空间(最后手段) |
重建表空间意味着导出数据、删除表空间、重建、再导入。只有在文件不可读、又没有可用备份时才考虑;它能解决问题,但代价远高于前两种。
修复后的验证
- 两个节点分别
startup,确认都能打开,不只是在节点一验证。 - 查
v$datafile/dba_data_files,确认所有数据文件路径都是+DATADG开头,没有残留本地路径。 - 查
v$tablespace和dba_tablespaces,确认表空间状态为ONLINE。 - 做一次小范围读写测试,确认没有坏块。
- 检查告警日志,确认没有新的 ORA-01157 或 ORA-01110。
风险提示
- 停集群、切归档、
rename数据文件都属于高风险操作,必须在维护窗口执行,并确认已有可用备份。 alter database rename file不搬文件,只改记录;先复制、后改名,顺序不能反。- 归档模式切换必须在
MOUNT状态;在OPEN状态执行会直接报错。 - RAC 下任何“打开数据库”的动作都要确认两个节点,单节点成功不代表集群正常。
- 删除原本地数据文件前,先确认数据库已经用新路径正常打开并运行过一段时间。
待核对
- ORA-01157 案例原文为 11g RAC,本文保留原路径(
/oracle/app/db、/app/oracle/11.2.0),在 19c 环境需替换为实际路径。 - 原文方式二(本文“方式一的变体”)的源文件名
DATADG、目标SYSTEM01.dbf与 rename 目标NCMAIL三处不一致,原文如此,执行前必须统一。 - 原文方式三(本文“方式二:RMAN”)的
file_id 7、+DATA/ora112/...为原文示例,需按实际环境替换。 - 方式三“重建表空间”原文只给了结论,未给命令;本文仅列步骤顺序,不提供可直接执行的脚本。
- 原文归档目录示例
/oracle/app/db/archivelog与+ARCHDG分别对应单机和 RAC,不要同时设置。 - 原文
show parameter recovery_file_dest;按原文保留,实际参数名为db_recovery_file_dest,执行时以show parameter db_recovery_file_dest为准。 - 原文在 RAC 归档步骤中标注
alter database open需双节点执行;RAC 下每个实例需分别启动/打开,实际以srvctl start database统一拉起更稳妥,此处保留原文说法。 - 文中
v$recovery_file_dest、v$archive_dest、v$datafile/v$recover_file查询和srvctl stop service的说明为补充内容,原文未涉及,用于补齐定位与验证环节。 - 原文末尾的表空间使用率 SQL 含
groupby、orderby、orderby1连写问题,本文按正确语法补空格后收录,字段与别名未改。
原文首发于微信公众号「止水研习社」。
文章评论