首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

拯救SQL Server数据库事务日志文件损坏的终极大招

编程知识
2024年07月17日 02:44

拯救SQL Server数据库事务日志文件损坏的终极大招

 

在数据库的日常管理中,我们不可避免的会遇到服务器突然断电(没有进行电源冗余),服务器故障或者 SQL Server 服务突然停掉,

头大的是ldf事务日志文件也损毁了,SQL Server服务器起来之后,发现数据库处于"Recovery Pending" 状态。

更麻烦的是该数据库没有任何备份或者备份已经比较久远;

当然这些都不是最难的,最难的是连资深DBA使出ATTACH_REBUILD_LOG和 DBCC CEHECKDBREPAIR_ALLOW_DATA_LOSS 选项等招数时候,

即使已经做好了最坏打算,做了丢失部分数据的准备,数据库还是无法上线。

 

本文将分享终极处理方法,帮助您成功恢复数据库。

 


 

测试环境: SQL Server 2022,Windows 2016

注意:奇技淫巧有风险,做任何操作之前注意先做备份! 

 

 

模拟环境

首先,在数据库 testdb 中创建 testObject 表,并不停插入所有对象数据。

在窗口一我们运行插入数据脚本,使用多次 CROSS JOIN,以获得足够多的数据,插入数据脚本实际是一个模拟的大事务。

--窗口1

CREATE DATABASE testdb
GO
USE testdb
GO        
SELECT * INTO testObject FROM sys.all_objects --前面脚本执行完成再执行下面的插入语句 INSERT INTO dbo.testObject SELECT o.* FROM sys.all_objects o CROSS JOIN sys.all_objects o1 CROSS JOIN sys.all_objects o2 CROSS JOIN sys.all_objects o3 CROSS JOIN sys.all_objects o4

返回信息如下

-- Msg 109, Level 20, State 0, Line 0
--A transport-level error has occurred when receiving results from the server. (provider: Shared Memory Provider, error: 0 - 管道已结束。)

 

在窗口二我们在关闭测试实例时,窗口一的插入事务仍然在运行。

这将使得数据库处于不一致状态,在数据库启动时,执行数据库恢复。

--窗口2
--执行完下面语句之后,移走ldf文件,模拟ldf文件损坏


SHUTDOWN WITH NOWAIT

数据库停服后,将testdb数据库 的ldf事务日志文件改名或者移到其他路径,重新启动SQL Server 服务,可以看到,testdb 数据库处于“恢复挂起”状态。

因为在停服时候,还有未提交的插入事务保存在ldf事务日志文件,需要在数据库启动时候把事务日志捞出来做crash recovery。

 

数据库启动之前,已经把ldf事务日志文件移动到别的地方

此时,我们已经有一个孤立的,不一致的数据库文件。

现在我们必须先离线数据库,把mdf文件复制到别的地方作为备份,然后删除数据库,为后续的附加ldf事务日志文件做准备

--窗口3

USE master
GO     
ALTER DATABASE [testdb] SET OFFLINE;

把mdf文件复制到别的地方作为备份,因为数据库离线了,并不会删除物理数据文件

--窗口4

USE master
GO     
DROP  DATABASE [testdb] ;

 

传统方法

使用 ATTACH_REBUILD_LOG 来重建ldf事务日志文件

--窗口5

USE master
GO    
CREATE DATABASE [testdb] ON
(FILENAME='E:\DataBase\testdb.mdf')
FOR ATTACH_REBUILD_LOG


GO  

报错信息如下

--文件激活失败。物理文件名称'E:\DataBase\testdb_log.ldf'可能不正确。
--无法重新生成日志,原因是数据库关闭时存在打开的事务/用户,该数据库没有检查点或者该数据库是只读的。如果事务日志文件被手动删除或者由于硬件或环境问题而丢失,则可能出现此错误。
--Msg 1813, Level 16, State 2, Line 8
--无法打开新数据库 'testdb'。CREATE DATABASE 中止。


到此为止,我们很可能只有去找备份文件还原了(如果有的话),否则可能就是一场灾难了。

 


 

新方法
接下来将介绍终极恢复数据库的方法,以帮助您度过劫难。

使用 CREATE DATABASE 语句中非官方文档记载(undocument)的命令,这个命令就是ATTACH_FORCE_REBUILD_LOG

这个命令会强制重建ldf事务日志文件,即使数据库检测到ldf事务日志文件和mdf数据文件之间有不一致的情况。

--窗口6

USE master
GO    
CREATE DATABASE [testdb] ON
(FILENAME='E:\DataBase\testdb.mdf')
FOR ATTACH_FORCE_REBUILD_LOG
GO  

返回信息如下

--文件激活失败。物理文件名称'E:\DataBase\testdb_log.ldf'可能不正确。
--新的日志文件 'E:\DataBase\testdb_log.ldf' 已创建。

数据库虽然恢复正常,但数据表依然无法访问

--窗口7

USE [testdb]
GO

SELECT TOP 10 *  FROM [dbo].[testObject]

SELECT COUNT(*)  FROM [dbo].[testObject]

报错信息如下

--Msg 824, Level 24, State 2, Line 18
--SQL Server 检测到基于逻辑一致性的 I/O 错误: pageid 不正确(应为 1:69856,但实际为 0:0)。在文件“E:\DataBase\testdb.mdf”中的偏移 0x000000221c0000 处,在数据库 ID 9 中的页面 (1:69856) 的 读取 期间发生。SQL Server 错误日志或操作系统错误日志中的其他消息可能会提供更多详细信息。这是一个威胁数据库完整性的严重错误条件,必须立即更正。请执行完整的数据库一致性检查(DBCC CHECKDB)。此错误可以由许多因素导致;有关详细信息,请参阅 https://go.microsoft.com/fwlink/?linkid=2252374。

 

使用最小数据丢失的方式,修复数据库

头两个命令将数据库分别置于紧急模式和单用户模式,这是我们执行 DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS 选项的前提。

最后一句命令是将数据库恢复多用户模式。

--窗口8
--使用最小数据丢失的方式,修复数据库

USE [master]
GO 
ALTER DATABASE [testdb] SET EMERGENCY
GO  
ALTER DATABASE [testdb] SET SINGLE_USER WITH NO_WAIT
GO  
DBCC CHECKDB([testdb],REPAIR_ALLOW_DATA_LOSS) WITH ALL_ERRORMSGS



--dbcc checkdb执行完毕之后执行下面语句,让数据库可以重新访问
ALTER DATABASE [testdb] SET MULTI_USER WITH NO_WAIT

DBCC CHECKDB返回信息如下,很多信息这里做了省略

可以看到有5924 个一致性错误,修复了 5924 个一致性错误,也就是全部修复了

--testdb的 DBCC 结果。

--Msg 8909, Level 16, State 1, Line 19
--表错误: 对象 ID 0,索引 ID -1,分区 ID 0,分配单元 ID 0 (类型为 Unknown),页 ID (1:69830) 在其页头中包含错误的页 ID。页头中的 PageId 为 (0:0)。
--        该错误已修复。
--Msg 8909, Level 16, State 1, Line 19
--表错误: 对象 ID 0,索引 ID -1,分区 ID 0,分配单元 ID 0 (类型为 Unknown),页 ID (1:69831) 在其页头中包含错误的页 ID。页头中的 PageId 为 (0:0)。
--        该错误已修复。
--Msg 8909, Level 16, State 1, Line 19
--data)释放。
--修复: 页 (1:70420) 已从对象 ID 1541580530,索引 ID 0,分区 ID 72057594045857792,分配单元 ID 72057594052673536 (类型为 In-row data)释放。
--修复: 页 (1:70421) 已从对象 ID 1541580530,索引 ID 0,分区 ID 72057594045857792,分配单元 ID 72057594052673536 (类型为 In-row data)释放
。。。

--对象 ID 1541580530,索引 ID 0,分区 ID 72057594045857792,分配单元 ID 72057594052673536 (类型为 In-row data): 无法处理页 (1:69866)。有关详细信息,请参阅其他错误消息。
--        该错误已修复。
--Msg 8928, Level 16, State 1, Line 19
--对象 ID 1541580530,索引 ID 0,分区 ID 72057594045857792,分配单元 ID 72057594052673536 (类型为 In-row data): 无法处理页 (1:69867)。有关详细信息,请参阅其他错误消息。
--        该错误已修复。

。。。

--sys.filetable_updates_2105058535的 DBCC 结果。
--对象“sys.filetable_updates_2105058535”在 0 页中找到 0 行。
--CHECKDB 在数据库 'testdb' 中发现 0 个分配错误和 5924 个一致性错误。
--CHECKDB 在数据库 'testdb' 中修复了 0 个分配错误和 5924 个一致性错误。
--DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。

数据库处于单用户模式

 

设置回多用户模式之后,尝试查询数据

--窗口9

--从数据行数来看,具体你是不知道丢失多少数据的,只能说能挽救多少是多少吧



USE [testdb]
GO


SELECT TOP 10 *  FROM [dbo].[testObject]

SELECT COUNT(*) AS'rowcount' FROM [dbo].[testObject]

数据是查询出来了,但是具体丢失多少数据,我们无法掌握

至少数据库最后一次checkpoint点之后的所有数据将会丢失。

 

 

 


 

总结

 

在传统的方法里面,还有一个方法就是 新建一个同名的空数据库作为傀儡数据库,然后替换傀儡数据库的数据文件

再对傀儡数据库执行DBCC CEHECKDB 的 REPAIR_ALLOW_DATA_LOSS 选项,但是实际上也不能保证100%有效

这个方法网上已经有相关文章,这里就不展开叙述了。

 

 

 


前几天帮一个网友恢复数据库,由于这个网友的数据库没有任何备份,并且遇到ldf事务日志损坏的问题,

起初使用ATTACH_REBUILD_LOG来重建日志文件不成功。在外网刚好搜索到ATTACH_FORCE_REBUILD_LOG这个命令,

最后总算帮这个网友尽最大努力挽回了数据。

 


最后提醒一下,附加没有ldf事务日志文件的数据库,并重建日志文件,有以下方法,其中有些方法已经废弃

DBCC REBUILD_LOG:已经废弃
sp_attach_single_file_db:已经废弃
ATTACH_REBUILD_LOG:推荐使用
ATTACH_FORCE_REBUILD_LOG:慎用

 

 

 

参考文章

https://www.mssqltips.com/sqlservertip/3579/how-to-attach-a-sql-server-database-without-a-transaction-log-and-with-open-transactions/
https://blog.sqlauthority.com/2016/11/04/sql-server-unable-attach-database-file-activation-failure-log-cannot-rebuilt/
https://vladdba.com/2022/08/31/recovering-master-database-with-corrupted-transaction-log-and-no-backups/

 

 

本文版权归作者所有,未经作者同意不得转载。

From:https://www.cnblogs.com/lyhabc/p/18306393/ultimate-solution-to-rescue-sql-server-transaction-log-file-corruption
本文地址: http://www.shuzixingkong.net/article/93
0评论
提交 加载更多评论
其他文章 js需要同时发起百条接口请求怎么办?--通过Promise实现分批处理接口请求
如何通过 Promise 实现百条接口请求? 实际项目中遇到需要发起上百条Promise接口请求怎么办? 前言 不知你项目中有没有遇到过这样的情况,反正我的实际工作项目中真的遇到了这种玩意,一个接口获取一份列表,列表中的每一项都有一个属性需要通过另一个请求来逐一赋值,然后就有了这份封装 真的是很多功
BigDecimal的精度与刻度
BigDecimal是Java中用于高精度算术运算的类。当您需要精确地处理非常大或非常小的数字时,例如在金融计算中,它特别有用。由于众所周知得原因,Double这种类型在某些情况下会出现丢失精度的问题,所以在需要对较为敏感的数据(比如与金额有关的)进行运算时,我们都会用BigDecimal。但是,用
BigDecimal的精度与刻度 BigDecimal的精度与刻度
共享库soname机制
目录前言共享库版本号共享库命名机制realnamesonamelinkname总结参考文章 前言 在使用第三方库时,我们会发现第三方库会提供一组文件,他们的后缀一般是.so(如libname.so),.so.x和.so.x.y.z。本文讨论他们之间的关系。 共享库版本号 共享库一般会由于修复bug或
共享库soname机制
Doris failed to initialize storage reader. tablet=106408, res=[NOT_IMPLEMENTED_ERROR]to be implemented
Apache Doris 2.3 以下的版本会存在一个 bug,导致数据在合并时存在异常,在后续查询该字段数据时会提示 [1105] [HY000]: errCode = 2, detailMessage = (192.168.15.228)[CANCELLED]failed to initiali
Doris failed to initialize storage reader. tablet=106408, res=[NOT_IMPLEMENTED_ERROR]to be implemented
Django DRF @action 装饰器
@action 装饰器在Django REST Framework (DRF) 中非常有用,它可以帮助你在ViewSet中创建自定义的动作,而不仅仅是依赖标准的CRUD操作(Create, Read, Update, Delete)。以下是 @action 装饰器的一些常见用法: 1. 创建自定义集
OceanBase 金融项目优化案例(union all 改写)
在工单系统上看到有一条sql问题还没解决,工单描述看到压测场景被cpu资源被这条sql打爆,目前影响到项目进度,比较紧急。 直接联系这位同学看看是否需要帮忙。 慢SQL: SELECT task.*, sc01.aab300 bjsjjg, (SELECT sc05.bsc012 FROM sc05
OceanBase 金融项目优化案例(union all 改写) OceanBase 金融项目优化案例(union all 改写) OceanBase 金融项目优化案例(union all 改写)
Microsoft宣布将在开发人员会议上专注于.NET Aspire
2024年7月15日微软宣布,其开发执行团队将在下个月的开发者大会上聚焦于使用 .NET Aspire 的云原生开发,以及结合人工智能的“现代 SQL”在 Microsoft Fabric 中的应用。微软的 Visual Studio LIVE! 2024 大会不仅是一个会议,而是创新、学习和社区庆
Microsoft宣布将在开发人员会议上专注于.NET Aspire Microsoft宣布将在开发人员会议上专注于.NET Aspire
基于 Vagrant 手动部署多个 Redis Server
环境准备 宿主机环境:Windows 10 虚拟机环境:Vagrant + VirtualBox Vagrantfile 配置 首先,我们需要编写一个 Vagrantfile 来定义我们的虚拟机配置。假设已经在 D:\Vagrant\redis 目录下创建了一个 Vagrantfile,其内容如下:
基于 Vagrant 手动部署多个 Redis Server 基于 Vagrant 手动部署多个 Redis Server 基于 Vagrant 手动部署多个 Redis Server