这篇文章是有点迟了,最近我的课堂上要引用这篇博文——所以我想不得不写了。本文是我以前的一篇关于存储引擎文章 的升级版本,本文中将加入DIFF 和ML 映射页的解释。
在以前的这系列博文中,我已解释了数据库文件中的一些基本存储:
• Anatomy of a record
• Anatomy of a page
• Anatomy of an extent
• IAM pages, IAM chains, and allocation units
有关分配的最后一块需要解释的地方就是其他用来跟踪分配映射的页: GAM 、SGAM 、PFS 、ML 和DIFF 映射页。本文所有的解释适用于SQL SERVER 2000 至迄今所有的版本。所有的这些页可以使用DBCC PAGE (方式3 )来列出,它将会以平常人能够阅读的形式列出分配跟踪的数据。
GAM 页
GAM 表示全局分配位图(global allocation map )。如果你还记得:数据库的数据文件被划为多个GAM 区间(只是概念上的,并没有物理上划分,不要混淆)。一个GAM 区间是GAM/SGAM /IAM 中位图跟踪的空间的总和:64000 区或者近4G 。这五种类型页的位图一样大,每1 位表示一个区,但是不同类型页的位表示不同的含义。
GAM 位图中每位的含义如下:
1 )位为1 表示该区可用(你可以将它看作是当前分配给了GAM 页了).
2 )位为0 表示该区已经被分配使用了。
混合区和统一区,上面的含义一致。
注意一件事:在每个GAM 区间开始处是一个GAM 区,该区包含跟踪该GAM 区间的全局分配页,这个区不能当作正常的页被分配。第一个GAM 区开始于文件的第0 页,其页的布局如下:
• 页0 :文件头页(另文介绍)
• 页1 :第1 个PFS 页
• 页2 :第1 个GAM 页
• 页3 :第1 个SGAM 页
• 页4 :2005 及以后未用
• 页5 :2005 及以后未用
• 页6 :第1 个DIFF 映射页
• 页7 :第1 个ML 映射页
SGAM 页
我记得去年曾经有一封email 讨论过SGAM 中的“S” 到底表示什么?这些年来,在微软内外各种名字都是用过,但是联机图书上的官方名称用的是共享全局 分配位图(Shared Global Allocation Map )。老实说,我们常称之为“es-gams” 而从不拼出它。
就像我上面说的,SGAM 位图与GAM 位图的结构和覆盖区间完全一致,就是位表示的意思不同:
1 )位为1 表示区是混合区且有可用页。
2 )位为0 表示区未作混合区,或者虽然是混合区时但其所有页均在使用中。(本质上,同样的情况也说明SGAM 被用来寻找还没有进行页分配的混合区)。
GAM ,SGAM 和IAM 页
让我们来将 GAM , SGAM 和 IAM 页(还记得吗?在 IAM 位图中,若区被分配给 IAM 链 / 分配单元,则该位为 1 )结合在一起,看一下各个位的组合情况:
你可以看到8 个组合中只有4 个是有效的,其它的会造成某种损坏,且可能导致各种可怕的情形。
ML 映射页
ML 代表最小日志(Minimally Logged )。这种页被用来在BULK_LOGGED 恢复模式中,跟踪自上次日志备份以来哪些区经过最小日志的修改操作。这样下次日志备份时除了正常备份日志,还要包括在位图中标明已修改的所有区。这种备份的区加上事务日志 就是自上次事务日志备份以来所发生的变化。一旦ML 页被读取,所有的位图都会被清除。如果你没有使用过BULK_LOGGED 恢复模式,那么ML 页是不会被使用的。
ML 位图与GAM 位图的结构和覆盖区间完全一致,就是位表示的意思不同:
1) 位为1 表示该区自上次日志备份来进过了最小日志操作的修改。
2) 位为0 表示该区未被修改。
DIFF 映射页
DIFF 表示差异(differential )。这种页被用来跟踪自上次完整备份以来哪些区被修改过。说DIFF 位图用来跟踪自上次差异备份以后的变化是一个常见的误解。一个差异备份包含自上次完整备份以来的所有修改过的区。使用差异备份可以大大节省恢复时间——可以避免必须恢复自上次完整备份到最后一次差异备份期间的日志备份(以后专门介绍)。所有的位图直到下次完整备份才会被清除。注意:所有上面的解释我并没有说是完整的数据库备份——因为完整或差异备份包括数据库、文件组和文件层次的备份。
DIFF 位图与GAM 位图的结构和覆盖区间完全一致,就是位表示的意思不同:
1 )位为1 表示该区自上次完整备份以来进行了修改。
2 )位为0 表示该区未被修改。
PFS 页
PFS 表示页可用空间。但是PFS 页跟踪的远不止这些。和GAM 区间相似,每个数据库文件同样也被分割成(概念上)PFS 区间。一个PFS 区间是8088 页或约64MB 。PFS 页中不是位图,它是字节图,每个字节表示PFS 区间中的一页(不包括PFS 页本身)。
字节中每位的含义如下:
1 )位0-2 :页中有多少可用空间
a)0x00 表示空
b)0x01 表示1~50% 满
c)0x02 表示51~80% 满
d)0x03 表示81~95% 满
e)0x04 表示96~100% 满
2 )位3 (0x08 ):页中是否至少有一个ghost 记录?
3 )位4 (0x10 ):是否为IAM 页?
4 )位5 (0x20 ):是否为混合页?
5 )位6 (0x40 ):页是否已分配?(分配状态位)
比如一个IAM 页的PFS 字节为0x70 (已分配 + IAM 页 + 混合页)。你可以使用DBCC PAGE 来查看PFS 页。
跟踪可用空间只适用于存储LOB 值(比如SQL SERVER 2000 中的text/image 类型;SQL SERVER 2005 中再加上varchar(max)/varbinary(max)/XML 类型以及行溢出数据)和堆数据页。因为只有这些页存储的数据不用排序,所以可以在任何位置插入。而像索引是有明确的顺序的,所以插入点是没有选择的。
注意一点:重置PFS字节并不是很直观。PFS字节不会完全重置(译注:比如清0)而是要等到重新分配页时。当页释放时,只是改变了PFS字节中的分配状态位——这样可以很方便的回滚释放动作。
下面是一个例子。在数据库中表T1 只有一行数据。使用DBCC PAGE 检查IAM 页如下:
PFS (1:1) = 0x70 IAM_PG MIXED_EXT ALLOCATED 0_PCT_FULL
如果我在一个显式事务中删除表,再执行DBCC PAGE ,结果如下:
PFS (1:1) = 0x30 IAM_PG MIXED_EXT 0_PCT_FULL
我们如果回滚事务,那么DBCC PAGE 的输出结果又变成:
PFS (1:1) = 0x70 IAM_PG MIXED_EXT ALLOCATED 0_PCT_FULL