备库ORA-01578和ORA-26040?多半是NOLOGGING挖的坑

发布时间:2026/10/13 17:18:26

备库ORA-01578和ORA-26040?多半是NOLOGGING挖的坑 值班时看到备库报ORA-01578我的第一反应不是盘坏了而是先问主库最近有没有人跑过大表append、索引rebuild、或者谁手贱建表时写了NOLOGGING。这套“条件反射”是在踩过几次坑之后形成的在Data Guard物理备库上这个错误十有八九不是硬件故障而是主库的NOLOGGING操作在备库侧留下了逻辑空洞备库读到空洞块时直接报ORA-01578随后还会跟一个ORA-26040。这两个错误放在一起基本就把问题定性了。本文把这套故障从成因、排查到修复的完整链路讲清楚包括我实测过的几种方案、各自适用边界以及日常怎么提前防。内容适合正在维护Oracle Data Guard的DBA、刚接手备库运维的同行也适合遇到报错后不知道从哪下手的值班人员直接照着操作。1. 错误类型与背后的机制1.1 ORA-01578与ORA-26040的报错含义先看两个错误本身。ORA-01578的意思是“Oracle检测到数据文件中的某个块存在损坏”通常报错会带上文件号和块号形如ORA-01578: ORACLE data block corrupted (file # 20, block # 12345) ORA-01110: data file 20: /oradata/users01.dbf看到这个别急着跑dbv或者做rman restore先看后面有没有第二个错误。如果紧接着出现ORA-26040: Data block was loaded using the NOLOGGING option那就能确认了这个块不是物理坏道也不是写中断而是NOLOGGING操作造成的“合法空洞”。意思是主库在生成这个块时没有写redo备库通过redo同步时拿不到对应数据块内容在备库侧就是空的或者旧数据残留一旦读到就报损坏。这里要理解一个关键点ORA-26040不是随机出现的它是Oracle对“已知未记录操作导致块损坏”给出的专门提示。看到它修复思路就完全转向了——不能再按物理损坏去恢复数据文件而是要按逻辑损坏来处理。1.2 NOLOGGING操作如何把备库“坑”了NOLOGGING这个词容易让人误解。它不是完全不写redo而是对某些特定操作只记录“变更元数据”不记录实际数据内容。设计初衷是减少redo量、加快大操作速度比如INSERT /* APPEND */直接路径加载CREATE TABLE AS SELECT如果表或表空间设置为NOLOGGINGALTER INDEX ... REBUILD或索引创建时的NOLOGGINGALTER TABLE ... MOVE配合NOLOGGING属性某些分区交换、MERGE等操作在特定模式下在单机环境这些操作没太大问题因为数据最终写在本地数据文件里磁盘上有真实数据。但放到物理备库场景就不一样了备库通过应用主库的redo来同步而NOLOGGING操作没有把实际数据写进redo备库只是收到了一个“这里变了”的通知不知道具体内容。于是主库数据文件里那个块是好的备库对应的块却永远缺失数据成了一个逻辑空洞。这个空洞平时可能不显形因为备库查询不一定读到那个块。只要某条SQL的访问路径扫到它立刻爆出ORA-01578加ORA-26040。也正因为这个特点很多备库故障往往不是切换时发现而是在跑报表、做备份校验、或者一致性检查时突然冒出来。注意备库的DB_UNRECOVERABLE_SCN视图和V$DATAFILE的UNRECOVERABLE_TIME列就是专门记录这类空洞的。判断一个数据文件有没有潜在NOLOGGING空洞可以从这里先摸底。2. 快速研判: 损坏范围与可恢复性评估2.1 抓取完整错误与告警日志遇到ORA-01578后第一步不是立即修复而是把信息抓全。至少需要拿到以下内容完整的SQL语句或操作上下文。如果是用户跑SQL触发让用户保留SQL文本和会话ID别急着杀掉会话。告警日志中对应的ORA-01110、ORA-26040、以及可能伴随的ORA-00600。损坏文件号、块号。这决定了你后面定位对象和选择恢复方案。主库最近几天是否有NOLOGGING操作记录。查V$DATAFILE的UNRECOVERABLE_TIME或者直接问主库侧做过什么变更。我常用的组合查询-- 备库执行 SELECT file#, name, unrecoverable_time, unrecoverable_change# FROM v$datafile WHERE unrecoverable_change# 0; SELECT file#, block#, blocks FROM v$database_block_corruption;第一句看哪些文件有未记录变更第二句是RMAN自动登记的坏块列表。如果V$DATABASE_BLOCK_CORRUPTION里有记录RMAN后续块恢复会直接识别如果这里没记录而报错仍然出现那可能是物理损坏或内存问题需要另查。2.2 定位损坏对象拿到file#和block#后下一步是映射到具体段也就是找出来“哪个表、哪个索引、哪个分区”中招了。这个映射SQL几乎是每次必用SELECT owner, segment_name, segment_type, partition_name, tablespace_name FROM dba_extents WHERE file_id file_id AND block_id BETWEEN block_id AND block_id blocks - 1;如果块正好落在某个段的extent里就能直接看到对象名。查到之后再到主库去看这个对象的属性SELECT table_name, logging FROM dba_tables WHERE owner owner AND table_name segment_name; SELECT index_name, logging FROM dba_indexes WHERE owner owner AND index_name segment_name;LOGGING列为NO就说明对象本身是NOLOGGING属性。但要注意一种情况即使对象默认是LOGGING只要会话级别或表空间级别设置了NOLOGGING或者用了ALTER SESSION强制同样会出问题。所以不要只看对象属性还要结合主库当时的操作记录。还有一种定位思路是用DBMS_REPAIR来确认块损坏范围但我一般只在不确定坏块数量、且需要跳过坏块读取数据时才用。常规修复前先定位对象会比直接skip更主动因为修复的最终目标不是绕过而是让备库重新可用。2.3 确认主库状态与可用备份这块最容易被忽略。很多人一看到备库坏块就开始从备份恢复结果恢复出来的数据文件比主库落后一大截重新应用redo时又出现gap最后两头难受。动手前必须确认三件事主库当前SCN。执行SELECT current_scn FROM v$database;备库当前已应用的SCN。执行SELECT applied_scn FROM v$archive_dest_status WHERE dest_id 1;或查询V$DATAGUARD_STATS里的apply_time、apply_scn。可用备份情况。执行rman target / list backup of datafile 20;重点不是“有没有备份”而是“备份归档能不能覆盖到主库当前SCN”。如果备份太旧数据文件restore后需要应用大量归档而归档里可能还包含了其他NOLOGGING操作的“空洞”等于修补了一个洞又埋了另一个雷。我一般把这三项列一个小表对比再决定方案。后面修复部分会具体说每种方案的适用前提。3. 修复方案选型3.1 最小代价的“跳过/重置”方案如果损坏块属于索引且该索引可以在主库重建那么最省事的方案不是从备份恢复备库而是在主库确认索引对应表数据本身没有NOLOGGING空洞。在主库执行索引重建或删除重建操作时保持LOGGING。主库产生的新redo会把重建后的索引块传到备库备库对应块被覆盖后坏块自然消失。这种方案严格来说没有在备库做“恢复”而是利用重新生成对象的方式消除空洞。它只适用于索引等可以从基表衍生的辅助对象。如果是普通表的数据块不能通过重建来解决因为表数据没有替代来源。还有一种思路是DBMS_REPAIR.SKIP_CORRUPT_BLOCKS它可以把坏块标记为跳过让查询不落地读取。但这是临时解法数据文件中缺失的内容并没有补回来。如果是非关键历史表、且业务能接受部分数据缺失可以应急如果是核心表我不建议用这个方案顶替正常恢复。3.2 块级介质恢复如果坏块范围很小并且有可用的备份rman backup包含该数据文件块级恢复是最快的物理修复手段rman target / restore datafile 20; recover datafile 20;但这里有个容易翻车的地方restore datafile是整文件恢复不是块恢复。真正的块级恢复命令是rman target / blockrecover datafile 20 block 12345;块级恢复只从备份取回指定块然后应用归档恢复到最新SCN。它的前提是备份中的这个块本身是完好的且归档日志连续覆盖到当前。问题在于如果这个块从一开始就是因为NOLOGGING而损坏而备份也是在这个“空洞”之后做的那备份里的块同样是坏的blockrecover不会解决问题。判断方法是查备份有效性rman target / validate datafile 20 block 12345;如果validate报同样的ORA-01578/ORA-26040说明备份块也是坏的物理恢复这条路走不通。3.3 基于SCN的不完全恢复/闪回如果损坏是最近一次NOLOGGING操作造成的且操作发生时间点很明确备库可以采用基于SCN的不完全恢复把数据文件回退到NOLOGGING操作之前再重新应用之后的归档。备库执行类似SHUTDOWN IMMEDIATE; STARTUP MOUNT; ALTER DATABASE RECOVER DATABASE UNTIL SCN 受损前的SCN; ALTER DATABASE OPEN;但这会拉大主备差距需要后续重新应用归档。实际操作中还要处理UNRECOVERABLE_CHANGE#的限制如果该数据文件的UNRECOVERABLE_CHANGE#已经高于回退点则回退后重新应用redo时还会再次遇到同样的空洞。如果环境开了闪回日志备库也可以用FLASHBACK DATABASE回到指定SCN前提是主库没有因为切换或重建清掉备库的闪回日志。这个方法比RECOVER UNTIL SCN快不少但依赖条件严格我在生产上用得不多。3.4 重建备库当坏块范围大、NOLOGGING操作频繁、备份也覆盖不了、或者备库已经落后太多时最干净的办法是重建备库。步骤是主库做增量备份或全量备份。用备份在备库端恢复数据文件。配置并重新启动Data Guard同步。可以选择两种备份建备方式# 方式一全量备份 RMAN BACKUP DATABASE PLUS ARCHIVELOG; # 方式二增量备份比全量更快 RMAN BACKUP INCREMENTAL FROM SCN 主库当前SCN - N DATABASE PLUS ARCHIVELOG;如果主库采用了增量备库incremental standby甚至可以只在主库备份增量、备库用增量合并减少数据传输量。重建备库听起来笨重但它能彻底消除所有NOLOGGING空洞也顺带修复其他潜在问题适合作为保底方案。4. 实操案例: 一次主库NOLOGGING索引重建引发的备库损坏修复4.1 故障现象某生产环境物理备库在夜间批量报表执行到一张大表时会话报错退出。值班同学截图ORA-01578: ORACLE data block corrupted (file # 7, block # 213456) ORA-01110: data file 7: /data/app/oradata/user_data_01.dbf ORA-26040: Data block was loaded using the NOLOGGING option我上了备库先查坏块记录然后查主库近期变更发现两天前有开发同事对一张大表的某个索引执行过ALTER INDEX ... REBUILD NOLOGGING。时间线完全吻合。4.2 排查过程与命令第一步备库查坏块SELECT file#, block#, blocks FROM v$database_block_corruption;结果就一行file 7 block 213456。第二步映射对象SELECT owner, segment_name, segment_type, partition_name FROM dba_extents WHERE file_id 7 AND 213456 BETWEEN block_id AND block_id blocks - 1;定位到xxx_INDEX是个普通索引段。第三步主库查索引状态和日志属性SELECT index_name, logging, status FROM dba_indexes WHERE index_name XXX_INDEX;结果是LOGGINGNO状态VALID。这就解释了为什么主库看起来没事主库索引的物理块是重建时写好的状态正常备库没有收到索引块数据只有“索引变了”的信息块内容停留在旧版本或全空状态。第四步确认备库当前apply是否停滞。查V$DATAGUARD_STATSSELECT name, value, unit FROM v$dataguard_stats WHERE name IN (apply lag, transport lag);数值都在秒级说明redo应用是通的只是这个块本身是坏的。4.3 修复执行因为损坏对象是索引直接走“主库重建、redo同步覆盖”的方案。注意重建时强制LOGGINGALTER INDEX xxx.xxx_index REBUILD ONLINE LOGGING;如果重建的索引体量很大可以考虑并行但并行度不要超过主库CPU核数的一半不然容易把主库IO打满ALTER INDEX xxx.xxx_index REBUILD ONLINE LOGGING PARALLEL 8;主库重建完成后redo会传到备库。备库需要确认是否已经在应用。如果备库MRP进程正常等一下再查坏块SELECT file#, block#, blocks FROM v$database_block_corruption;正常情况下返回no rows然后让报错会话重跑SQL验证即可。这里有个教训重建索引时开发用的是NOLOGGING他们本意是想加速但忽略了这是DG环境。重建完成后我在主库把该索引显式改成LOGGINGALTER INDEX xxx.xxx_index LOGGING;虽然改属性不会立刻把未来的操作变成必然LOGGING因为表空间级别、会话级别仍可能覆盖但至少对象默认属性是安全的。5. 常见问题速查与避坑清单5.1 容易踩的坑坑一把逻辑空洞当物理坏块处理。看到ORA-01578就启动RMAN整文件恢复恢复完发现坏块还在。原因就是备份块本身也是空洞。先查有没有ORA-26040没有也要用V$DATABASE_BLOCK_CORRUPTION和UNRECOVERABLE_CHANGE#辅助判断不要急着restore。坑二在主库直接在线重建索引但没注意表空间是否NOLOGGING。如果索引所在表空间被设置了NOLOGGING重建即使指定LOGGING也可能不生效。检查顺序表空间级 对象级 会话级。执行前先看一眼SELECT tablespace_name, logging FROM dba_tablespaces WHERE tablespace_name...;坑三备库恢复后没有重新启用Data Guard。有些同学在备库做了RECOVER DATABASE UNTIL SCN之后忘了恢复MRP进程导致备库一直停滞。恢复完要记得ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;坑四用块恢复时没有确认备份时间点。如果备份是NOLOGGING操作之前的块恢复后需要应用大量归档。如果这个归档本身又包含NOLOGGING产生的record还是会再次损坏。排查时一定要把主库NOLOGGING操作时间点找出来和备份时间、归档覆盖范围做对比。5.2 日常防线这类问题完全可以提前布控不用每次都等备库报错再救火。我现在的做法是监控UNRECOVERABLE_CHANGE#。定期在备库查询V$DATAFILE中UNRECOVERABLE_CHANGE#大于0的文件一旦发现立即找主库确认近期NOLOGGING操作。主库侧限制NOLOGGING操作。对于必须做的NOLOGGING操作先评估对象是否会被DG同步影响。像索引重建这种完全可以改成LOGGING性能损失通常可接受直接路径加载如果数据量大优先考虑在维护窗口做并事后在主库跑一次校验。备库定期做坏块校验。用RMAN BACKUP VALIDATE CHECK LOGICAL DATABASE或者DBV扫关键表空间能提前发现潜在空洞而不是等报表跑挂。备份策略留够冗余。至少保留一份在NOLOGGING操作之前的有效备份以备块级恢复时使用。没有历史备份的DG环境遇到严重NOLOGGING损坏时往往只能重建备库代价更大。把NOLOGGING操作纳入变更流程。任何涉及NOLOGGING的DDL/加载操作都要在变更单里注明“是否影响DG备库”并安排备库校验步骤。没有流程约束光靠技术手段总有人会忘记。我个人在实际操作中还有一个习惯备库报ORA-01578时先冷静下来在笔记本上把file# / block# / 对象 / 主库变更时间 / 备份时间五列写全再决定方案。大多数翻车案例都是因为信息没抓全就动手。这套方法帮我处理过不止一次同类故障每次走完流程基本都能在半小时内给出结论并完成修复。希望这篇整理也能让你下次遇到ORA-26040时不用从“查资料”开始。
延伸阅读

更多相关文章

2026/10/13 17:18:26

短信验证码接口防刷设计:从限频到双因子令牌的完整方案

短信验证码接口防刷设计,这个题目我在不同团队里前前后后折腾过好几轮了。老实说,每次以为把防护做到位了,没过多久总会被新的刷法打脸。短信通道不像别的业务接口,它直接和成本、用户体验、账号安全三件事挂钩,被刷爆…

2026/10/13 17:18:26

多微网能量互联优化调度:面向低碳经济目标的Matlab建模与实现

三个微网如果各自闷头调度,光伏大发的时候用不完、负荷高峰的时候又得高价买电,这本身就是一种浪费。把它们用联络线连起来,让功率在微网之间流动,再叠加上碳排放约束,就是我这次想聊的核心问题——面向低碳经济运行目…

2026/10/13 17:13:26

开放式代码审查:一种可落地的开源协作范式

1. 这不是代码审查工具,而是一套可落地的开源协作范式“open-code-review”这个标题乍看像某个新出的 GitHub Action 或 CLI 工具,但实际翻遍主流包管理器、GitHub Trending 和 Hacker News 近三个月热帖,都找不到一个叫这个名字的成熟项目。…

2026/10/13 18:28:53

Kettle 9.3 跨云ETL实战:S3/GCS连接、JDK17适配与Spoon启动避坑指南

简介:本资源为Kettle(Pentaho Data Integration)最新9.3版本的官方安装包百度网盘直链,面向数据工程师、ETL开发人员及大数据初学者,解决国内用户因网络限制难以获取国际开源ETL工具的问题。资源以1个14KB的docx文档形…

2026/10/13 18:28:53

AGENTS.md:给AI编程建一份项目记忆说明书

不跟你绕圈子,这篇文章的出发点是我这段时间反复踩到的一个问题:我把同一个项目背景跟AI编程工具讲了不下十遍,每次新建会话它都像第一天上班一样,对我的代码库一无所知。模型的对话窗口装得下上下文,但它记住的东西在…

2026/10/13 18:28:53

MySQL到HBase实时同步:Maxwell+Kafka+Thrift生产实践

1. 项目概述:为什么用 Maxwell Kafka Thrift 这套组合打通 MySQL 到 HBase 的链路在某数据中台的实际演进过程中,我反复遇到一个高频痛点:业务库 MySQL 里沉淀了大量高价值的实时交易、用户行为、订单状态变更数据,但这些数据天…

2026/10/13 18:28:53

PS2键盘模拟程序:从PS/2协议到单片机固件实现的完整指南

简介:面向单片机与嵌入式开发者,这份PS2键盘模拟程序源码演示了如何用单片机模拟PS/2键盘行为,适用于自动化测试、特殊输入设备等需要注入键盘信号的场景。资源共3个文件,包含1个C源文件与2个头文件,压缩包仅2KB&#…

2026/10/13 18:23:47

微信小程序二手交易源码数据库.zip:从导入到跑通与二次开发

简介:微信小程序二手物品交易源码包,面向计算机专业毕业设计、课程设计及小程序开发实战学习者,提供一套以Java为后端、微信小程序为前端的完整可运行项目。系统实现商品发布、分类浏览、关键词检索、用户登录与订单管理等典型交易流程&#…

2026/10/13 5:19:27

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/13 17:09:18

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/12 12:54:07

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/13 0:04:41

基于Triton部署YOLO目标检测:从训练脚本到线上服务

简介:这份资源面向希望将目标检测模型落地到生产环境的深度学习开发者与算法工程师,聚焦于用 Triton Inference Server 部署 YOLOv9 的完整实战方案,解决从训练权重到线上推理服务之间的工程化难题。压缩包共 16 个文件,约 886KB&…

2026/10/13 0:04:41

手把手教你云端部署Qwen-Image-2.1:从GPU选型到在线文生图服务

Qwen-Image-2.1 这个开源的图像生成模型,最近在内容创作和 AI 应用圈子里热度相当高。它属于通义 Qwen 系列里的视觉生成分支,让我眼前一亮的是它对中文长文本的理解能力——以前用那些老方案生成带中文文字的图,十个里九个是“乱码印刷体”&…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑