简介面向Oracle数据库运维人员和DBA的ORA-00257故障处理文档聚焦归档日志空间耗尽后数据库写入受阻、抽取任务中断等典型场景适合需要快速定位问题并恢复实例可用性的初中级技术人员参考。资源包仅包含1个doc文件约76KB以文字说明配合关键命令片段组织内容篇幅紧凑便于在服务器排障现场直接查阅也可作为日常巡检、应急演练和故障复盘的备忘材料。该文档已有580人学习说明其在实际运维场景中具有一定参考价值。内容围绕归档日志占用比例判断、恢复区路径与容量确认、物理日志清理以及RMAN空间回收等关键环节展开并对选择性删除、crosscheck标识过期对象、释放后复查占用比例等风险点作出提示。文档以问题背景、处理思路和注意事项递进组织重点信息集中适合在时间紧张的故障处置中快速翻阅。读者可据此理解归档日志满故障的排查脉络掌握空间释放与验证的基本思路降低误删风险和重复排查成本。1. ORA-00257 归档日志满先分清“删文件”和“销账本”凌晨两点半数据抽取任务停在半路应用日志里只剩一行ORA-00257: archiver error. Connect internal only, until freed。这是典型的 Oracle 归档日志满归档写不进闪回恢复区ARCH 进程被挂起所有依赖写入的会话跟着停摆。手上已经有这份 ORA-00257 错误处理文档的人多半知道要删日志但真正容易出错的地方几乎都在同一处用rm把归档目录清了个干净回头一查v$flash_recovery_area_usage百分比依然没有下降。Oracle 记录的是自己的账本物理空间释放了逻辑空间还挂在控制文件里。这份文档给的正是两步删物理文件再进 RMAN 用crosscheck和delete expired把账销掉。适合手上兼着 Oracle 运维、被归档满停过业务、想要一套能照着敲下来的流程的人。2. 定位 FRA 占用从告警日志到 v$ 视图的三条证据链动手删任何东西之前先把“到底是谁把空间占了”这个账算清楚。现场最常见的错误是连数据库都还没进去凭df -h看到一个分区 100% 就开删删完发现占满的是另一块盘。FRAFast Recovery Area闪回恢复区里不只有 archivelog还有备份片、控制文件自动备份、闪回日志哪一类都可能单独把配额顶满。2.1 先从告警日志确认报错原文和发生时间用 root 登录服务器之后第一件事是切到 oracle 用户不要用 root 直接碰数据文件属主一乱后面rman找不到文件又得多排查一轮。# 切到 oracle 用户后续所有数据库操作都在这个身份下做 su - oracle # 先问数据库自己的告警日志在哪比凭记忆猜路径靠谱 sqlplus -S / as sysdba EOF set lines 200 pages 100 col name for a28 col value for a70 select name, value from v$diag_info where name in (Diag Trace,Default Trace File); EOFv$diag_info里Default Trace File就是当前实例 alert log 的完整路径11g 之后基本都指向$ORACLE_BASE/diag/rdbms/db_name/instance/trace/alert_instance.log。拿到路径之后直接 grep# 取最近 20 条 ORA-00257看看是偶发还是持续刷 ALERT/u01/app/oracle/diag/rdbms/orcl/orcl/trace/alert_orcl.log grep -n ORA-00257 $ALERT | tail -20 # 顺带看 ARCH 进程有没有反复启停、有没有归档目的地写失败 grep -nE ARCH|Archive|destination $ALERT | tail -40判断标准很简单如果同一分钟内连着出现多条ORA-00257说明 archiver 在反复重试数据库基本处于挂起状态写入业务已经受影响如果一天只有零星一两条且能自愈说明是 FRA 配额卡在临界点属于预警而非故障。这一步的价值在于确认“确实是归档满”而不是归档目的地配置错了、或者备库连不上导致归档发不出去后两种情况的处置方式完全不同。2.2 分子和分母v$flash_recovery_area_usage 与 v$recovery_file_dest文档里的核心一步是select * from v$flash_recovery_area_usage;这条 SQL 给出的比例是“占 FRA 配额的比例”不是“占磁盘的比例”这两个数经常差很远先想清楚再看结果。-- 分母FRA 配额上限注意参数单位是字节 select name, value, value/1024/1024/1024 as quota_gb from v$parameter where name db_recovery_file_dest_size; -- 分子按文件类型拆开的占用明细 select file_type, percent_space_used, percent_space_reclaimable, number_of_files from v$flash_recovery_area_usage; -- 另一视角FRA 整体水位space_reclaimable 是关键 select name, space_limit/1024/1024/1024 as limit_gb, space_used/1024/1024/1024 as used_gb, space_reclaimable/1024/1024/1024 as reclaimable_gb, number_of_files from v$recovery_file_dest;几个字段要会读percent_space_used到 89.78% 这种数值时说明离报错只差一轮日志切换原文里那台机器就是这样被顶住的percent_space_reclaimable才是“现在就能立刻还回来的比例”它对应的是那些已经被删除物理文件、或者已经过期、但控制文件里还挂着记录的对象。如果 used 是 95% 而 reclaimable 是 0说明没有可回收的只能扩配额或者往别处搬如果 used 95%、reclaimable 60%那走一遍crosscheck delete expired就能立刻降下来。12c 之后v$flash_recovery_area_usage多了一个con_id列在 11g 上执行会报ORA-00904: CON_ID: invalid identifier删掉这一列即可同理v$recovery_file_dest在部分版本上是单行视图多租户环境下要换成v$pdbs相关的 PDB 视角去查。2.3 v$archived_log看清哪些已经销账、哪些还挂着v$archived_log是归档记录的主要依据deleted和status两列直接告诉你控制文件当前的态度。-- 按序列号倒序看最近 20 条归档含大小和状态 select * from ( select recid, sequence#, first_time, next_time, blocks * block_size / 1024 / 1024 as size_mb, deleted, status, completion_time, name from v$archived_log where dest_id 1 order by sequence# desc ) where rownum 20;字段含义要记牢deleted YES表示 RMAN 已经把这笔账销掉了空间已经从 FRA 配额里扣回来deleted NO表示账上还在、占着配额status取A是 available文件在、可用D是 deleted记录删了X是 expired配置了crosscheck之后确认文件已不在。所以如果你手工rm过一批文件却还没跑crosscheck你会看到一批deleted NO, status A的记录但去磁盘上找这些name一个都找不到这就是“物理已删、逻辑未销”的典型状态也是后面必须在 RMAN 里补一刀的原因。顺手再确认一下归档模式和归档目的地避免在已经开归档但目的地配置飘了的库上瞎折腾select log_mode, force_logging, database_role from v$database; select dest_id, status, destination, archived_seq#, applied_seq# from v$archive_dest_status where status INACTIVE;2.4 文件系统侧核一遍别让视图和现实对不上数据库视图算的是账文件系统才是实物。两边都看一眼能提前发现“归档写到别的路径去了”或者“FRA 里混了别的东西”。# 查看 FRA 根目录实际占用和磁盘剩余 du -sh /backup/flash_recovery_area df -h /backup # 按归档子目录拆开看哪一天的最占地方一目了然 du -sh /backup/flash_recovery_area/*/archivelog/* 2/dev/null | sort -h | tail -10 # 统计 7 天前的归档文件数量和总大小 find /backup/flash_recovery_area -type f -name *.arc -mtime 7 | wc -l find /backup/flash_recovery_area -type f -name *.arc -mtime 7 \ -printf %s\n | awk {s$1} END {printf 合计 %.2f GB\n, s/1024/1024/1024}提示du出来的总量通常会比space_used略小因为 FRA 配额里还算上了控制文件自动备份和闪回日志的预留差个百分之几很正常差一倍以上就是路径对不上或者有软链接得先查清楚再删。3. 删除物理归档文件rm 之前必须做的四件事原文的思路是“删物理文件然后进 RMAN 释放逻辑空间”这个顺序本身没问题问题在于很多人把第一步做成了rm -rf /backup/.../archivelog整目录一锅端。文档里专门注明“这是新的数据库服务器没有其他的操作记录”也就是说原文那个场景是无备份依赖的一次性清理。换成生产库照抄恢复链就断了。下面四件事是我每次动手前的固定动作。3.1 先确认这些归档有没有被备份、有没有备库在消费删归档之前必须回答两个问题这些日志备份过吗有备库或者下游在追吗两个都是“是”才能动。# 进 RMAN 看最近两天的归档备份情况summary 输出够用且快 rman target / # RMAN 交互命令 RMAN list backup of archivelog from time sysdate-2 summary; RMAN list backup summary;list backup of archivelog ... summary会按备份集列出覆盖的归档区间看到连续的序列号区间就说明这一段有备份兜底。如果输出是RMAN-06758: no backup of archived log found说明这批归档压根没备份过这时候删掉它们等于放弃这段时间的恢复能力只能靠全备加在线日志风险自己评估。备库和下游的情况用v$archive_dest_status看重点看archived_seq#、applied_seq#和status-- 备库/下游追到哪个序列号了主库当前又到哪个序列号 select dest_id, status, destination, archived_seq#, applied_seq# from v$archive_dest_status where status INACTIVE; select max(sequence#) as current_seq from v$log_history;规则很直白主库上准备删的最小序列号必须大于所有活跃目的地已applied_seq#的最大值并且留一段缓冲。备库追得慢的时候删归档就是亲手制造归档 GAP等到切换或者补数据那天再发现就晚了。3.2 按时间窗口圈定删除范围而不是整个目录原文按2012_06_10、2012_06_11这样的日期目录来挑着删思路是对的只删窗口外的保留窗口内的。在 Linux 上用-mtime更省事但它是按 24 小时整除算的边界有点绕所以务必先列后删。FRA/backup/flash_recovery_area/ORCL/archivelog # 第一步只列不删确认边界对不对 find $FRA -type f -name *.arc -mtime 7 \ -printf %TY-%Tm-%Td %10s %p\n | sort | head -20 # 第二步统计这批要删多少量级心里有数 find $FRA -type f -name *.arc -mtime 7 | wc -l find $FRA -type f -name *.arc -mtime 7 \ -printf %s\n | awk {s$1} END {printf 预计释放 %.2f GB\n, s/1024/1024/1024} # 第三步真正删除。用 -delete 比 -exec rm -f {} \; 少一次进程创建 find $FRA -type f -name *.arc -mtime 7 -delete-mtime 7表示修改时间在 7 天以前准确说是 7×24 小时之前的整日边界如果你要“保留最近 N 天”用-mtime N是符合直觉的要按分钟精度算就换成-mmin $((7*24*60))。删除动作加-type f限定只匹配普通文件避免哪天目录结构变了把目录也带上。如果库上开了备库这个窗口要按applied_seq#反推不能拍脑袋按天算。我的习惯是先跑一遍select min(sequence#) from v$archived_log where deletedNO and completion_time sysdate-8;确认这个序列号在所有备库侧都存在且已应用再决定删到哪。3.3 保留窗口怎么定按恢复目标倒推不按磁盘剩余空间倒推保留多久不是拍脑袋是 RPO 和备份策略倒推出来的。参考下面这张表场景建议保留依据每日全备 归档备份可接受丢 1 天37 天至少覆盖最近两轮全备之间的全部归档每周全备 每日增量810 天要覆盖一个完整备份周期增量恢复时日志不能断有物理备库实时同步保留到备库applied_seq#追平再加缓冲按追平延迟算不看天数单机、从未做过归档备份不要用rm这条路先把 RMAN 全备跑通再谈清理有合规留存要求先归档到磁带或对象存储再删本地本地只留恢复窗口内的表格里最后一行最容易被忽略很多团队的“归档备份”只是把文件拷贝到另一块盘仍然在同一台机器上机器一挂两个副本一起没这种“备份”在清理决策里不能算数。3.4 删完之后数据库并不知道crosscheck 存在的意义这一步是整篇文档的技术核心。Oracle 控制文件里记录着每个归档文件的路径、大小、时间戳和状态rm只动了文件系统控制文件的记录原封不动FRA 配额也照旧按space_used算。于是就出现了那个经典画面磁盘上腾出 80Gv$flash_recovery_area_usage还是 95%。crosscheck干的事情就是拿着控制文件里的清单去操作系统逐个核对文件在标记为 available文件不在标记为 expiredstatus X。注意它只标记不删记录所以跑完crosscheck空间依然不会降必须再补一条delete expired才真正把记录删掉、把配额还回去。这两条命令是“核对”和“销账”的关系缺一不可。注意crosscheck会顺带校验备份片和镜像副本对象多的时候能跑十几分钟甚至更久。生产上不要无脑crosscheck archivelog all用crosscheck archivelog from time sysdate-30;限定范围速度差好几倍。4. RMAN 释放逻辑空间crosscheck 与 delete expired 的完整流程4.1 连接方式target / 与 catalog 的取舍最省事的连法是 OS 认证su - oracle rman target /target /走的是操作系统认证要求当前用户在dba组里$ORACLE_SID指向目标实例。如果报ORA-01031: insufficient privileges先用id看看组再看sqlnet.ora里是不是把SQLNET.AUTHENTICATION_SERVICES关掉了。用了恢复目录的团队就连 catalog# 恢复目录方式好处是控制文件重建后备份元数据还在 rman target / catalog rman_owner/passwordcatdb两种方式在crosscheck和delete expired的行为上没区别区别在元数据存哪控制文件方式下一旦控制文件重建或者被覆盖历史备份记录就丢了crosscheck会把所有找不到的归档都标成 expiredcatalog 方式元数据独立保存重建控制文件之后还能对得上账。生产库我一般建议上 catalog尤其是备份保留策略比较复杂的场景。4.2 crosscheck archivelog all 做了什么rman target /RMAN crosscheck archivelog all; using target database control file instead of recovery catalog allocated channel: ORA_DISK_1 channel ORA_DISK_1: SID128 device typeDISK crosschecked archive log ... Crosschecked 412 objects输出的关键行是最后那句Crosschecked N objects其中的统计里包含了“校验通过”和“标记为 expired”的数量。RMAN 还会把结果写进v$archived_log文件不存在的那些status变成X。想验证的话跑一句-- 看有多少归档已经被标记为 expired文件已不在 select status, count(*), sum(blocks*block_size)/1024/1024/1024 as gb from v$archived_log where dest_id 1 group by status;status X的那一行就是待销账的量。这个数字应该跟你在磁盘上删掉的大致对得上如果差很多说明有别的路径的归档也被rm了或者db_recovery_file_dest指向的目录不止一个。如果对象很多crosscheck archivelog all会跑很久可以分段来RMAN crosscheck archivelog from time sysdate-30 until time sysdate-7; RMAN crosscheck archivelog from sequence 1200 until sequence 1800 thread 1;按序列号分段最精确尤其是归档量大、文件名规律但时间戳被cp弄乱过的场景。4.3 delete expired 与 delete archivelog 的边界销账用这条RMAN delete expired archivelog all; List of Archived Log Copies for database with db_unique_name ORCL Key Thrd Seq S Low Time ------- ---- ------- - ------------------- ... Do you really want to delete the above objects (enter YES or NO)? YES deleted archived log ... Deleted 412 EXPIRED ARCHIVED LOG objects它会提示确认输入YES才执行。脚本里用noprompt跳过交互RMAN delete noprompt expired archivelog all;必须分清楚的三条命令命令删记录删物理文件用错后果delete expired archivelog all删不删本来就没有基本安全只处理已标记 expired 的对象delete archivelog all删删灾难级会把还在的归档一起删掉delete archivelog until time sysdate-7删删需要配合备份策略否则删掉未备份的日志现场出事故的多数是第二条本来想销账手一快敲成delete archivelog allRMAN 问都没问就把物理文件删了。所以脚本里务必用expired这个限定词别用缩写或者历史命令补全。4.4 更稳的路子让 RMAN 一步完成删除和销账rm加crosscheck这套流程适合“已经删了、需要补账”的应急场景日常更推荐从数据库侧直接删RMAN 会先删文件再更新控制文件不会出现账实不符。RMAN delete archivelog until time sysdate-7 backed up 1 times; RMAN delete archivelog all completed before sysdate-3; RMAN backup archivelog all delete input;第三条是长期方案备份和清理绑在一个动作里备份成功才删输入天然不会断链。配上删除策略等于给delete archivelog all上了锁RMAN configure archivelog deletion policy to backed up 2 times to device type disk;配完之后没攒够两份备份的归档delete archivelog all根本删不动这就是我常说的“后悔药”出过一次事之后我每个库都会先配这条策略再谈清理。配额不够用的时候扩db_recovery_file_dest_size也是正解之一前提是底层文件系统真有空间-- 扩大到 320G同时生效不改重启注意别超过文件系统可用空间 alter system set db_recovery_file_dest_size 320G scope both;改完再查一次v$recovery_file_dest确认space_limit变了、space_used没超过新上限然后观察一轮日志切换有没有再报 ORA-00257。扩容只是把时间买回来策略不改下次还会满。5. 避坑与排查五条现场记录5.1 删完物理文件占用比例一点没降现象rm掉一批归档df显示空间回来了v$flash_recovery_area_usage的percent_space_used还是原来那个数v$recovery_file_dest.space_used也没变甚至日志切换之后马上又报 ORA-00257。原因Oracle 的 FRA 账本记在控制文件里只删文件不通知数据库space_used不会重算space_reclaimable也不会自动增加。很多人到这一步以为是“删得不够多”继续rm越删越乱。解决跑crosscheck archivelog all;把不存在的文件标成 expired再跑delete expired archivelog all;。执行完立刻查v$recovery_file_destspace_used应该明显下降、number_of_files减少。如果降得不够说明还有别的文件类型占着比如BACKUP PIECE或FLASHBACK LOG回到第 2 章的v$flash_recovery_area_usage按file_type逐个看。5.2 crosscheck 跑到一半卡住或者报 ORA-19588现象crosscheck archivelog all长时间没输出或者报出ORA-19588: archived log record ... is no longer valid、RMAN-08120: WARNING: archived log not deleted。原因前一种多半是对象太多几万个文件加上存储响应慢后一种通常是控制文件里的记录和实际情况已经严重不一致或者有并发 RMAN 任务在同时操作同一批归档两个会话互相打脸。解决先确认没有别的 RMAN 会话在跑select sid, serial#, program from v$session where program like %rman%;有就等它结束或者协商停掉。然后按序列号或者时间段分段 crosscheck别一次全量RMAN crosscheck archivelog from sequence 1000 until sequence 2000 thread 1;分段跑还有个额外好处能定位到具体哪个区间出了问题排查起来有落点。5.3 delete expired 提示 0 objects但空间确实没回来现象crosscheck跑完了接着delete expired archivelog all返回RMAN-06207: WARNING: 0 objects not deleted或者干脆显示Deleted 0 EXPIRED ARCHIVED LOG objects。原因三种可能。一是crosscheck那一步实际没标出 expired文件还在或者路径写错二是归档在v$archived_log里deleted已经是YES早就销过账占空间的另有其物三是你连的不是同一个库或者同一个实例RAC 环境下连到节点 2 去查节点 1 删的文件。解决按顺序验证。先select status, count(*) from v$archived_log where dest_id1 group by status;看X有多少再select file_type, percent_space_used, number_of_files from v$flash_recovery_area_usage;看占用大头到底是哪一类最后select instance_name, host_name from v$instance;确认连对了实例。RAC 里 FRA 一般是共享存储但归档路径按线程分目录确实存在“这个节点看不到那个节点文件”的错觉。5.4 归档删过头恢复时缺日志现象某次误删之后做时间点恢复或者备库补数据时报ORA-00308: cannot open archived log、ORA-01110: data file ...RMAN 提示需要的序列号找不到。原因删除窗口没有按备份链倒推删掉了还没备份、或者备库还没应用的归档。rm这种操作没有“回收站”删了就是删了。解决短窗口内可以尝试从备库、从磁带回捞对应序列号捞不到就只能恢复到最后一个可用归档点接受数据丢失。真正该做的是事前预防配configure archivelog deletion policy to backed up 2 times to device type disk;并且所有清理动作都走 RMAN 而不走rm。删之前一条 SQL 确认备库追平select dest_id, applied_seq#, status from v$archive_dest_status where status INACTIVE; select max(sequence#) from v$log_history;5.5 FRA 满了之后连 RMAN 备份都跑不起来现象ORA-00257 之后想先做一次全备再删归档结果 RMAN 报ORA-19809: limit exceeded for recovery files、ORA-19804: cannot reclaim ... bytes disk space备份直接失败。数据库这边写入也全挂应用报连接超时。原因FRA 里没有可回收对象space_reclaimable为 0RMAN 建备份片也需要往 FRA 写形成死锁式困局要备份才能删要删才能备份。解决先把db_recovery_file_dest_size临时扩大到一个有余量的值前提是文件系统有空间让 RMAN 能落一个小的归档备份或者把这次备份直接写到 FRA 之外的位置rman target /RMAN backup archivelog all format /backup/rman_arch_%U delete input;format指定到另一块盘绕开 FRA 配额。备份成功、delete input生效之后空间自然回来再把db_recovery_file_dest_size调回合理值。另外要检查一下log_archive_dest_1是不是直接指到了 FRA如果是应急时可以先alter system switch logfile观察 archiver 状态确认没有堆积再继续。6. 把应急动作变成常态容量、策略与每日巡检应急流程跑通只是止血真正让它不再复发靠两件事配额留够余量清理交给策略而不是人。6.1 参数侧给 FRA 留出至少一轮全备的空间一个实用的估算FRA 配额 ≥日归档量 × 保留天数最大一次全备的大小× 1.5。日归档量可以从v$archived_log算-- 近 7 天平均每天的归档量单位 GB select round(sum(blocks*block_size)/1024/1024/1024/7, 2) as avg_gb_per_day from v$archived_log where dest_id 1 and completion_time sysdate - 7;把这个数字乘以保留天数再加上全备体积的 1.5 倍冗余就是配额下限。低于这个值的库我会直接把db_recovery_file_dest_size调上去而不是靠“勤删”维持因为人一定会忘。6.2 脚本侧一条巡检 SQL 加一个定时任务每天跑一次超过 80% 就告警别等到 95% 才动手#!/bin/bash # fra_check.shFRA 水位巡检超过阈值就输出告警行 THRESHOLD80 sqlplus -S / as sysdba EOF set head off feedback off pages 0 select case when percent_space_used $THRESHOLD then ALERT: FRA used || round(percent_space_used,2) || % else OK: FRA used || round(percent_space_used,2) || % end from v$flash_recovery_area_usage where file_type ARCHIVED LOG; EOF挂到 crontab 里每天早八点跑输出走邮件或者日志采集。逻辑很简单关键是阈值要早于故障点80% 触发时你还有一天时间从容处理95% 触发时已经在救火了。6.3 验证一次清理是否真的生效每次清理完我用同一组三条 SQL 交叉验证不靠感觉-- 1. 配额水位是否下降 select space_limit/1024/1024/1024 gb_limit, space_used/1024/1024/1024 gb_used, space_reclaimable/1024/1024/1024 gb_reclaim from v$recovery_file_dest; -- 2. 归档状态分布X 应该被清空 select status, deleted, count(*) from v$archived_log where dest_id 1 group by status, deleted; -- 3. 最近一次日志切换是否正常完成 select sequence#, first_time, completion_time from v$archived_log where dest_id 1 order by sequence# desc fetch first 5 rows only;三条都对上才算这次处理结束对不上就回到第 2 章重新定位不要在没验证的情况下收工。血泪经验是最早我也觉得rm快、直接、省事直到有次在备库追得慢的库上删多了一天做恢复演练时补了整整一个下午的日志。从那以后我每次动归档之前都会强制走一遍“查备库 applied_seq#、查备份覆盖区间、配 deletion policy”这三步再开始删。希望帮到你。本文还有配套的精品资源点击获取