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

拯救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,以获得足够多的数据,插入数据脚本实际是一个模拟的大事务。

--窗口1CREATE DATABASE testdb
GO
USE testdb
GO        
SELECT * INTO testObject FROM sys.all_objects--前面脚本执行完成再执行下面的插入语句 INSERT INTO dbo.testObject SELECT o.* FROM sys.all_objects oCROSS JOIN sys.all_objects o1CROSS JOIN sys.all_objects o2CROSS JOIN sys.all_objects o3CROSS 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事务日志文件做准备

--窗口3USE master
GO     
ALTER DATABASE [testdb] SET OFFLINE;

把mdf文件复制到别的地方作为备份

--窗口4USE master
GO     
DROP  DATABASE [testdb] ;

 

传统方法

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

--窗口5USE master
GO    
CREATE DATABASE [testdb] ON
(FILENAME='E:\DataBase\testdb.mdf')
FOR ATTACH_REBUILD_LOGGO  

报错信息如下

--文件激活失败。物理文件名称'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)的命令使用出问题,微软是概不负责的。

--窗口6USE 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' 已创建。

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

--窗口7USE [testdb]
GOSELECT 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]
GOSELECT 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/

 

 

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/745028.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

On July

STAYING IN HOME 7月3日放假回家,这段时间大致是起床挖洞、晚上打球、外卖度日。完全的"宅",计划去练车,不巧的是打球崴脚了,只能闭关一下了。刚回家的那几天全是凌晨四五点睡,这几天好转一些,有意控制早点,不然窗帘一拉,起床就是下午三四点。每次起床就是吃完…

openEuler arm 环境源码编译mysql 8.0.37

部分参考博客 https://blog.csdn.net/ghpanxt/article/details/119387253 1、安装依赖:yum install -y openssl-devel ncurses-devel libaio libaio-devel libtirpc-devel openldap-devel openldap git bison 【注意】:对于openEuler操作系统,还需要安装rpcsvc-proto依赖,具…

Windows安装MySQL8

Windows安装MySQL8 0.下载 社区版最新版:https://dev.mysql.com/downloads/installer/ 各版本:https://downloads.mysql.com/archives/installer/Windows (x86, 32-bit), MSI Installer,迅雷下载 企业版 ... 1. 安装 1). 双击官方下来的安装包文件2). 根据安装提示进行安装安…

全网最适合入门的面向对象编程教程:18 类和对象的 Python 实现-多重继承与 PyQtGraph 串口数据绘制曲线图

本文主要介绍了Python中创建自定义类时如何使用多重继承、菱形继承的概念和易错点,同时讲解了如何使用PyQtGraph库对串口接收的数据进行绘图。全网最适合入门的面向对象编程教程:18 类和对象的 Python 实现-多重继承与 PyQtGraph 串口数据绘制曲线图 摘要: 本文主要介绍了 P…

【笔记】圆方树

【笔记】圆方树 1 定义 仙人掌: 所有边都至多被包含在一个环中。2 构建 给一个点和它所在的所在的所有点双连边,同时,我们定义方点为虚点(即表示点双的点),圆点为原图上的点。 注意,是所有点双,所以一个割点会连向多个点双。同时,由定义得,该图有且仅有圆方边,因为圆…

缓存穿透、缓存击穿、缓存雪崩的场景以及解决方法

缓存穿透、缓存击穿、缓存雪崩的场景以及解决方法都是缓存惹的祸 在项目开发中,我们的数据都是要持久化到磁盘中去,比如使用 MySQL进行持久化存储,但是呢由于流量越来越大,查询速度也逐渐变慢了起来,于是我们决定!使用缓存!然而使用缓存导致会经常面临三座大山!缓存穿透!!…

CSS Case Insensitive Attribute Selector All In One

CSS Case Insensitive Attribute Selector All In One CSS 大小写敏感的属性选择器CSS Case Insensitive Attribute Selector All In OneCSS 大小写敏感的属性选择器/* case sensitive, only matches "case_sensitive" */ [class=case_sensitive] {background: pink;…

玄机-第一章 应急响应- Linux入侵排查

玄机-第一章 应急响应- Linux入侵排查 简介 账号:root 密码:linuxruqin ssh root@IP 1.web目录存在木马,请找到木马的密码提交 2.服务器疑似存在不死马,请找到不死马的密码提交 3.不死马是通过哪个文件生成的,请提交文件名 4.黑客留下了木马文件,请找出黑客的服务器ip提交…

关于Win10 Penetration系统内置kali虚拟机WSL报错的解决方法

关于Win10 Penetration系统内置kali虚拟机WSL报错的解决方法: Win10 Penetration下载地址:https://pan.baidu.com/s/16b4_j9wuK_81G4uJKhNZyA?pwd=bj7t 提取码:bj7t Win10 Penetration是什么? Windows10 Penetration Suite Toolkit within Kali Linux是一个集成了各种渗透…

JMeter上传文件接口教程—01

Content-Type: multipart/form-data; 格式步骤: 1、添加HTTP Request、填写好HOST、URL等信息,这一步如果没有接口文档参照,可以去F12或者Fiddler抓包,我们这里重点讲没有接口文档的情况下如何做, 如果除了文件以外,还有表单数据,还是需要放在Parameters里边的。 2、上传…

如何在 Android 项目中应用 OpenCV?

如何在 Android 项目中应用 OpenCV? 流程总览导入 OpenCV 库 在 Android 项目中配置 OpenCV 创建人脸识别器 识别并裁剪人脸区域 显示裁剪后的人脸图片具体实现 导入 OpenCV 库先去 OpenCV 官网下载 OpenCV 的 Android 库并解压:https://opencv.org/releases/ 在项目中点击 f…

Android 开发学习笔记

Android 开发学习笔记 基本概念 Android 应用程序由一些零散的有联系的组件组成,通过一个工程 manifest 绑定在一起。在 manifest 中,描述了每一个组件以及组件的作用,其中有 6 个组件,它们是 Android 应用程序的基石。Android 有四大组件(也有说六大组件的,外加 Intent …