引:本文基于SQLServer数据库mdf数据文件的存储结构,描述的是数据库中一些跨页记录的存储方法。本文为北亚数据恢复中心内部研究成果,目前仅发布于51CTO,转载
引:本文基于SQL Server数据库mdf数据文件的存储结构,描述的是数据库中一些跨页记录的存储方法。本文为北亚数据恢复中心内部研究成果,目前仅发布于51CTO,转载时请与作者联系。
40002000200020002000
78
78401780341
78sql server 80,3)
m_slotCnt = 1 m_freeCnt = 3065 m_freeData = 5125
Slot 0 Offset 0x60 Length5029
Record Type = FORWARDED_RECORD RecordAttributes = NULL_BITMAPVARIABLE_COLUMNS
Record Size = 5029
Memory Dump@0x000000000D30A060
0000000000000000: 3200080001000000 03000003 00cb0b9b 2...............
0000000000000010: 13a59362 62626262 62626262 62626262...bbbbbbbbbbbbb
0000000000000020: 62626262 62626262 62626262 62626262bbbbbbbbbbbbbbbb
0000000000000030: 62626262 62626262 62626262 62626262bbbbbbbbbbbbbbbb
……
在第80页中,有一条记录slot 0,起始为96字节,长度为5029,记录类型为 forwarded_record.这条记录就是forwarding_stub中指向的溢出记录,记录着第78页中slot0数据记录的真实数据。
这是一条完整记录,和一般记录格式略有差异,最大的不同是在记录中加入了一列变长数据。这一变长列加在记录的最后,只是存储引擎使用,对上层是透明的。同时记录的列信息也发生了变化。
列信息里的变长列数加1,而总列数不发生变化。变长列偏移数组里多出一项,用来指定加入的数据列的结束偏移,这个变长列的长度其实是固定的,都是10字节,应该是考虑到存取性能才把这个数据放在了记录的最后。这列数据其实不是一列标准的列数据,应该是一个forwarding_stub的结构体数据。里边也是存储了一个rowid指针,用8字节保存了指向移出前的记录的位置指针。
这个加入的列数据的定位解析还有点特殊。它在列信息中的列数据结束偏移是非常规的,是按溢出类型格式存储的。它的值会大于8192字节,其实是真实数值加了0x8000。
现在来具体解释下上面的这条forwarded记录:
此记录头部状态A的值为0x32,解释为有可变长列,有null位图的forwarded 移出记录。记录总长度为5029字节数。列信息数据为03000003 00cb0b9b13a593。根据列信息结构来解析可得,总列数为3,是包含a、b、c三个字段。Null位图都为0,表示没有为空的列。变长列数也为3,这里是包含了变长列b、c和增加列。后边的结束偏移数组有3个,占用6字节,分别表示这3个变长列数据的结束位置。前两个很容易理解,第三个是0x93A5,转为十进制为37797,这明显是不正常的,真实的偏移值应为此值减去0x8000,即为0x13A5,转十进制为5029。这个值在前面的记录总长度处见过,不是巧合。
这样就可以手工的取出每一个字段值了。取出最后一列的值,会发现它特殊一点:
0004 4e00000001000000 。数据长度为10字节,跟forwarding很相似,只是在头部多加了一个字节的00。字段里的rowid记录了原来的forwarding记录的地址,这里是(1:78:0),这个地址指针正是指向前面我们看到的那条forwarding记录。
下面通过一幅图来总结下此节讲解的forwarding和forwarded记录的整体结构。
图Forwarding记录和forwarded 记录的相互连接关系
下图是在winhex中的解析展示: