天天看点

恢复SQL Server被误删除的数据

《恢复SQL Server被误删除的数据(再扩展)》

地址:http://www.cnblogs.com/lyhabc/p/4620764.html

曾经想实现Log Explorer for SQL Server的功能,利用ldf里面的日志来还原误删除的数据

这里有一篇文章做到了,不过似乎不是所有的数据类型都支持

以下为译文:http://raresql.com/2011/10/22/how-to-recover-deleted-data-from-sql-sever/

在我使用SQLSERVER的这些年里面,大部分人都会问我一个问题:“能不能恢复被删除的数据??”

现在,从SQLSERVER2005 或以上版本能很容易能够恢复被删除的数据

(注意:这个脚本能恢复下面的数据类型的数据 而且兼容CS 排序规则)

image

text

uniqueidentifier

tinyint

smallint

int

smalldatetime

real

money

datetime

float

sql_variant

ntext

bit

decimal

numeric

smallmoney

bigint

varbinary

varchar

binary

char

timestamp

nvarchar

nchar

xml

sysname

让我来用demo来解释一下我是怎么做到的

现在你需要创建一个存储过程来恢复你的数据

恢复SQL Server被误删除的数据
恢复SQL Server被误删除的数据

View Code

恢复你的数据

执行了下面的存储过程之后你会发现会显示出刚才删除的数据

恢复SQL Server被误删除的数据

解释

究竟他是如何工作的?让我们来一步一步来,这个过程涉及到7个步骤:

步骤1:

我们需要获得SQLSERVER删除的数据记录.使用标准SQLSERVER函数fn_dblog,我们能够容易的获得事务日志记录(包括

已删的数据。不过,我们只需要事务日志中选中的被删数据,所以我们的过滤条件需要包含3个字段 Context, Operation & AllocUnitName)

We need to get the deleted records from sql server. By using the standard SQL Server function fn_blog, we can easily get all transaction log (Including deleted data. But, we need only the selected deleted records from the transaction log. So we included three filters (Context, Operation , AllocUnitName).

Context (‘LCX_MARK_AS_GHOST’and ‘LCX_HEAP’)

Operation (‘LOP_DELETE_ROWS’)

AllocUnitName(‘dbo.aa’) –- Schema + table Name

Context可以说明是堆表还是聚集表

Operation:删除操作

AllocUnitName:分配单元名称,表名

下面是一个代码片段

这个查询会返回不同列的信息,但是我们只需要选择[RowLog Contents 0]列,去获得被删除的数据的内容

RowLog content 0列的内容类似于这样

“0x300018000100000000000000006B0000564920205900000

00500E001002800426F62206A65727279″

步骤2:

现在,我们已经删除了数据,这些数据以hex码的形式放在事务日志里,这些hex码是有规律的,我们根据这些规律可以很容易恢复这些数据。

不过在恢复这些数据之前,我们需要理解这些格式。这些格式在KalenDelaney’s SQL Internal’s book.的书里面有讲解

1 Byte : Status Bit A

1 Byte : Status Bit B

2 Bytes : Fixed length size

n Bytes : Fixed length data

2 Bytes : Total Number of Columns

n Bytes : NULL Bitmap (1 bit for each column as 1 indicates that the column is null and 0 indicate that the column is not null)

2 Bytes : Number of variable-length columns

n Bytes : Column offset array (2x variable length column)

n Bytes : Data for variable length columns

所以, hex码的“RowLog content 0″列的内容就等价于

“Status Bit A +Status Bit B +Fixed length size +Fixed length data +Total Number of Columns +NULL Bitmap +Number of variable-length columns +NULL Bitmap+Number of variable-length columns +Column offset array +Data for variable length columns.”

更详细的可以参考:SQL Server2008存储结构之堆表、行溢出

关于数据行的结构我们还可以采用稍微宏观一些的视角来查看。
恢复SQL Server被误删除的数据
  
恢复SQL Server被误删除的数据

步骤3:

现在,我们需要解剖RowLog Content o列的内容(我们删除的数据的Hex码),利用上面的数据行的结构

[Fixed Length Data] = Substring (RowLog content 0, Status Bit A+Status Bit B + 1,2 bytes)

[Total No of Columns]= Substring (RowLog content 0, [Fixed Length Data] + 1,2 bytes)

[Null Bitmap length] = Ceiling ([Total No of Columns]/8.0)

[Null Bytes]= Substring (RowLog content 0, Status Bit A+ Status Bit B +[Fixed Length Data] +1, [Null Bitmap length] )

Total no of variable columns = Substring (RowLog content 0, Status Bit A+ Status Bit B + [Fixed Length Data] +1, [Null Bitmap length] + 2 )

Column Offset Array= Substring (RowLog content 0, Status Bit A+ Status Bit B + [Fixed Length Data] +1, [Null Bitmap length] + 2 , Total no of variable columns*2 )

Variable Column Start = Status Bit A+ Status Bit B + [Fixed Length Data] + [Null Bitmap length] + 2+( Total no of variable columns*2)

恢复SQL Server被误删除的数据

步骤4:

现在我们已经将hex码切开了(0x300008000100000002000001001300604F7D59),所以,我们能找到删除的行的某列的数据是否为null值

根据NULL位图。为了完成将NULL Bytes的hex码转换为二进制格式(正如之前讨论的,1表示行中对应的那一列为null,而0则表示对应的列有实际的数据)

如果还不是明白的童鞋可以看一下我写的这篇文章:《SQLSERVER中NULL位图的作用》

恢复SQL Server被误删除的数据

步骤5:

现在,我们已经做了初步的数据分割 (Step-3) 和null值判断(Step-4) 。然后我们需要使用代码片段去获得列数据,例如:列名,列大小,精度,范围

和最重要的叶子的null位(确保列数据是固定长度的(<=-1表示可变长度)或者固定长度的(>=1))

使用下面的SQL语句

与(Step-1,2,3,4) 获得的数据表做join连接,根据allocunits.[Allocation_Unit_Id]。

现在我们知道表和表中的数据信息,那么我们需要利用这些数据去将 [RowLog Contents 0] 列里的hex码的数据插入到表中的相应列

现在我们需要关心每一列的数据究竟是固定长度的还是可变长度的

恢复SQL Server被误删除的数据

步骤6:

我们收集了每列的hex格式的数据。现在我们需要利用[System_type_id]去转换这些数据回去正确的数据类型

每一种数据类型都有不同的数据类型转换机制。

恢复SQL Server被误删除的数据

步骤7:

最终我们做一个数据透视表,你会看到最后的结果:被删的数据回来了!

注意:这些数据只是展示出来并没有自动插入回表中,你需要将这些数据重新插入回去表中!

恢复SQL Server被误删除的数据

我的测试

经过测试,作者写的这个存储过程还是有些问题

如果你创建的测试表的数据类型有xml或者是一些text数据类型的字段会有报错

但是一般的数据类型则不会,例如nvarchar这些

还有不要在存储过程的最后加

否则会报错

总结

实际上这个存储过程还是挺有研究意义的,对于想做一个跟Log Explorer for SQL Server软件功能差不多的软件出来

还是有可能的,跟着作者的思路,一步一步实现

苦于最近太忙,先分享出来,以后再研究这个存储过程了~

如有不对的地方,欢迎大家拍砖o(∩_∩)o 

支持date类型 感谢园友 dwchaoyue

恢复SQL Server被误删除的数据
恢复SQL Server被误删除的数据

2015-12-17 补充

注意:脚本中大量使用了reverse函数来进行转换,因为reverse函数的定义是返回字符串值的逆序,不是字节的逆序

那么就会导致有些数据类型是按字节逆序的,就会出错

恢复SQL Server被误删除的数据

在SQL Server中,sys.fn_PhysLocFormatter这个函数也是使用reverse函数进行RID逆序,当遇到81-FE之间的字节时 被认为是双字节字符组合在一起参与逆序运算

所以得出来的某些结果也是错的,详细请参考《SQL Server性能调优实战》 P115

函数的逻辑是,每个字节加上相应的位数

比如 2这个数字是在第二个字节位置的,那么公式就是2*POWER(2,8) =512

相应进制

二进制后面加8个0

十六进制后面加2个0

恢复SQL Server被误删除的数据
恢复SQL Server被误删除的数据
恢复SQL Server被误删除的数据
恢复SQL Server被误删除的数据

只要学过计算机基础都不难理解的

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

继续阅读