拯救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数据文件之间有不一致的情况。

请记住,非官方文档记载(undocument)的命令使用出问题,微软是概不负责的。

--窗口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/

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

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

  1. SQL Server数据库事务日志序列号(LSN)介绍

    原文:http://blog.csdn.net/tjvictor/article/details/5251463     日志序列编号(LSN)是事务日志里面每条记录的编号. 当你执行一次备份时,一些 ...

  2. SQL Server数据库事务日志存储序列

    原文 原文:http://blog.csdn.net/tjvictor/article/details/5251351   如果你的数据库运行在完整或是批量日志恢复模式下,那么你就需要使用作业(job ...

  3. SQL SERVER数据库删除LOG文件和清空日志的方案

    原文:SQL SERVER数据库删除LOG文件和清空日志的方案 数据库在使用过程中会使日志文件不断增加,使得数据库的性能下降,并且占用大量的磁盘空间.SQL Server数据库都有log文件,log文 ...

  4. 第十七周翻译-SQL Server中事务日志管理的阶梯,级别5:以完全恢复模式管理日志

    SQL Server中事务日志管理的阶梯,级别5:以完全恢复模式管理日志 作者:Tony Davis,2012/01/27 翻译:赖慧芳 译文: 该系列   本文是Stairway系列的一部分:SQL ...

  5. SQL Server中事务日志管理的步骤,第5级:完全恢复模式管理日志(译)

    SQL Server中事务日志管理的步骤,第5级:完全恢复模式管理日志 作者:Tony Davis,2012/01/27 系列 本文是进阶系列的一部分:SQL Server中事务日志管理的步骤 当事情 ...

  6. SQL Server无法收缩日志文件 2 因为逻辑日志文件的总数不能少于 2问题

    SQL Server无法收缩日志文件 2 因为逻辑日志文件的总数不能少于 2问题 最近服务器执行收缩日志文件大小的job老是报错 我所用的一个批量收缩日志脚本 USE [master] GO /*** ...

  7. SQL Server 2008收缩日志文件--dbcc shrinkfile参数说明

    原文:SQL Server 2008收缩日志文件--dbcc shrinkfile参数说明 DBCC SHRINKFILE 收缩相关数据库的指定数据文件或日志文件大小. 语法 DBCC SHRINKF ...

  8. 如何读懂SQL Server的事务日志

    简介 本文将介绍SQL Server的事务日志中记录了哪一些信息,如何来读懂这些事务日志中信息.首先介绍一个微软没有公开的函数fn_dblog,在文章的接下来的部分主要用到这个函数来读取事务日志. f ...

  9. [转]SQL SERVER数据库删除LOG文件和清空日志的方案

    本文转自:https://www.cnblogs.com/ShaYeBlog/archive/2012/09/04/2670505.html 数据库在使用过程中会使日志文件不断增加,使得数据库的性能下 ...

  10. SQL Server 2008无日志文件附加数据库

    1.新建一个同名数据库. 2.停止数据库服务,覆盖新建的数据库主文件(小技巧:最好放在同一个磁盘里面,把新建的数据库主文件删掉或移开,再把要恢复的数据库主文件剪切过去,这样就可以节省时间.) 3.启动 ...

随机推荐

  1. pageoffice 6 实现数据区域填充(插入文本、图片、word、excel等)

    在实际的Word文档开发中,经常需要自动填充数据到Word模板中,以生成动态的Word文档. 例如: 1.我们可以根据数据库表中已保存的个人信息,设计好一个简历模板docx文件,然后通过代码将这些个人 ...

  2. java学习之旅(day.08)

    类与对象的关系 类是一种抽象的数据类型,是对某一类事物的描述,但并不代表具体的事物,如动物与狗的关系,类描述的是某一类事物具备的共同特点 对象是抽象概念的具体实例 能够展现出功能,体现出特点的是具体的 ...

  3. Stenciljs 学习之搭建项目

    框架介绍 stenciljs 是用于构建可重用.可扩展的设计系统的工具链.生成在每个浏览器中运行的小型.超快且 100% 基于标准的 Web Component. 更对介绍请参考官方网站 创建项目 使 ...

  4. Python 潮流周刊#52:Python 处理 Excel 的资源

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  5. 《最新出炉》系列入门篇-Python+Playwright自动化测试-48-Route类拦截修改请求-上篇

    1.简介 在日常工作和学习中,自动化测试的时候:在加载页面时,可能页面出现很多不是很重要或者不是我们所关注的,这个时候我们就可以选择不加载这些内容,以提高页面加载速度,节省资源.例如:可能页面上图片比 ...

  6. Docker 启动 Redis 就停止解决方案(2022-3)

    启动命令如下: docker run -itd \ -p 6379:6379 \ --name myredis \ -v /home/redis/redis.conf:/etc/redis/redis ...

  7. docker部署php8.0 nginx1.18 mysql5.7 dnmp环境

    php8.0 nginx1.18 mysql5.7 #安装docker wget -O /etc/yum.repos.d/ali_docker-ce.repo https://mirrors.aliy ...

  8. 一个问题:六位八段数码管(Verilog)

    [基本信息] 需求:verilog程序,显示任意六位字符或数值,包含点号,且能够按需点亮位数.(学习篇) 芯片型号:cyclone Ⅳ EP4CE10F17C8 数码管属性:六位.八段 [最终成果图] ...

  9. Redis单线程

    Redis是基于Reactor模式开发的网络事件处理器,这个处理器是单线程的,所 以redis是单线程的. 为什么它是单线程还那么快呢? 主要有以下几个原因: 一.纯内存操作 由于Redis是纯内存操 ...

  10. 规则引擎easyRules中组合规则的使用

    这两天想要做支付路由,要根据支付信息将支付请求转发到不同的支付渠道,可能要用到规则引擎,于是研究了一下开源的规则引擎产品.规则引擎核心知识与开源产品对比选型 ,这篇文章对规格引擎和开源产品有详细的介绍 ...