拯救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. XML Schema 复杂元素类型详解:定义及示例解析

    在XML Schema(XSD)中,复杂元素是指包含其他元素和/或属性的XML元素.复杂元素可以分为四种类型: 空元素: 仅包含其他元素和/或属性的元素. 仅包含其他元素的元素: 不包含文本内容,只包 ...

  2. HTML——超链接标签

    一.超链接标签的基本使用 超链接是浏览者和服务器的交互的主要手段,也叫超级链接或a链接,是网页中指向一个目标的连接关系,这个目标可以是网页.网页中的具体位置.图片.邮件地址.文件.应用程序等. 超链接 ...

  3. c#使用webView2 访问本地静态html资源跨域Cors问题 (附带代理服务helper帮助类)

    背景 在浏览器中访问本地静态资源html网页时,可能会遇到跨域问题如图. 是因为浏览器默认启用了同源策略,即只允许加载与当前网页具有相同源(协议.域名和端口)的内容. WebView2默认情况下启用了 ...

  4. react做购物车的功能

    父组件 import React, { Component } from 'react' import Lists from '../components/Lists' export default ...

  5. .NET5 .NET CORE 使用Apollo

    Apollo默认有一个"SampleApp"应用,"DEV"环境 和 "timeout" KEY. nuget 中下载 "Com. ...

  6. (九)selenium实现12306模拟登录

    登陆的唯一困难在于验证码的识别,此处使用第三方平台超级鹰进行验证码识别. from selenium import webdriver import time from PIL import Imag ...

  7. ColorEasyDuino上手指南

    介绍 ColorEasyDuino是嘉立创推出的一块Aduino开发板(类似物),具有丰富的外设接口:uart.i2c.spi.adc.pwm等:开发板设计参考原型是Arduino Uno,采用的芯片 ...

  8. leetcode | 103. 二叉树的锯齿形层序遍历 | JavaScript实现

    题目 给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 .(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行). 思路 按照正常的层序遍历,然后再对下标为奇数的数组进 ...

  9. 泛型模板化设计DEMO

    泛型模板化设计DEMO 1. 定义Result泛型类 package com.example.core.mydemo.java.fanxing; public class Result<T> ...

  10. PackageScanner

    package com.cmb.cox.utils;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;im ...