鸿 网 互 联 www.68idc.cn

存储引擎-存储结构之二:页

来源:互联网 作者:佚名 时间:2013-11-04 09:32
说理论,总是枯燥的,先来段搞笑视频,清清脑 模特兒走秀摔倒集錦: 原文地址: 继续存储引擎揭秘系列,今天讨论页结构。页是用来存储记录的。一个页是数据库文件中的一个 8192 字节段。页在数据文件中开始于 0 字节,并按 8192 字节对齐。下面是一个页的基

说理论,总是枯燥的,先来段搞笑视频,清清脑

模特兒走秀摔倒集錦:

 

原文地址:

继续存储引擎揭秘系列,今天讨论页结构。页是用来存储记录的。一个页是数据库文件中的一个 8192 字节段。页在数据文件中开始于 0 字节,并按 8192 字节对齐。下面是一个页的基本结构图:

 

 


页面分成个部分:BUFFER、PAGEHEADER、DATA、OFFSET TABLE

BUFFER:显示了指定页面的缓冲信息。由于它是一个内存中结构,所以仅当页面处于内存中时候才有效.

PAGEHEADER:显示指定页面的所有报头字段信息。

DATA:显示每行数据的具体存储.

OFFSET TABLE:显示了所有行偏移矩阵的内容.

页头部

页头部大小为 96 字节。在这部分我最想做的事是使用 DBCC PAGE 来看一个页头部,然后解释一下所有的字段含义。我使用以前《 page split 》文章用的数据库,下面是 DBBC PAGE 部分输出:

DBCC TRACEON (3604)

DBCC PAGE ('pagesplittest', 1, 143, 1);

GO

m_pageId = (1:143)     m_headerVersion = 1     m_type = 1
m_typeFlagBits = 0x4   m_level = 0             m_flagBits = 0x200
m_objId (AllocUnitId.idObj) = 68   m_indexId (AllocUnitId.idInd) = 256 
Metadata: AllocUnitId = 72057594042384384 
Metadata: PartitionId = 72057594038386688        Metadata: IndexId = 1
Metadata: ObjectId = 2073058421  m_prevPage = (0:0)  m_nextPage = (1:154)
pminlen = 8            m_slotCnt = 4     m_freeCnt = 4420
m_freeData = 4681      m_reservedCnt = 0   m_lsn = (18:116:25)
m_xactReserved = 0    m_xdesId = (0:0)    m_ghostRecCnt = 0
m_tornBits = 1333613242  

下面是所有字段的解释(注意页中字段并不是按下面顺序存储排列的):

  • m_pageId
  • 这个字段标明了文件 ID 及页在该文件中的位置。在本例中( 1:143 )
  • m_headerVersion
  • 页头部版本。自从 7.0 以来,这个值总是为 1 。
  • m_type
  • 页类型,你可能见到的页类型如下:
  • 1 - 数据页。这种页存储堆或聚集索引的叶节点中的数据记录。
  • 2 - 索引页。这种页存储聚集索引的非叶节点 或非聚集索引的所有结点 的索引记录
  • 3 - 文本混合页。这种文本页存储小段的 LOB 值以及文本树的内部。这种页可被同一索引 / 堆的分区的 LOB 值所共享。
  • 4 - 文本树页。这种文本页存储一个单独列的大段的 LOB 值。
  • 7 - 排序页。这种页存储在一次排序操作中的中间结果。
  • 8 - GAM 页。这种页存有一个 GAM 区间(每个数据文件逻辑上被分割成约 4GB 大小的段,这个“约 4GB ”就是一个页中的位图所能表示的区)中所有区的分配信息:一个区是否已经被分配? GAM 表示全局分配映射( G lobal A llocation M ap )。第一个 GAM 页是每个文件的第 2 页。
  • 9 - SGAM 页。这种页也是存有一个 GAM 区间中所有区的分配情况:一个区是否可以分配混合页? SGAM 表示共享 GAM 。第一个 SGAM 页是每个文件的第 3 页。
  • 10 – IAM 页。这种页包含一个 GAM 区间中哪些区已分配给一个索引( SQL SERVER 2000 中)或分配单元( 2005 中)。 IAM 表示索引分配映射( Index Allocation Map )。
  • 11 - PFS 页。这种页存有一个 PFS 区间(每个数据文件逻辑上被分割成约 64MB 大小的段,这个“约 64MB ”就是一个页中的字节所能表示的页)中每个的页的分配和可用空间的信息。 PFS 表示页的可用空间。第一个 PFS 页是每个文件的第 1 页。
  • 13 - 启动页。这种页含有数据库的信息。每个数据库只有一个启动页,它是数据文件 1 的第 9 页。
  • 15 - 文件头页。这种页包含文件的信息。每个文件一个文件头页,是文件的第 0 页。
  • 16 - 差异映射页 (DIFF) 。这种页包含有自上次完整备份以来一个 GAM 区间中已发生改变的区的信息。第一个 DIFF 页是每个文件的第 6 页。
  • 17 - ML 映射页。这种页包含有自上次备份以来一个 GAM 区间中哪些区在 BULK-LOGGED 模式下发生了大容量日志操作。你为了大容量加载或重建索引而将恢复模式变为 BULK-LOGGED ,有了这种页就不用担心打断备份链了。第一个 ML 页是每个文件的第 7 页。
  • m_typeFlagBits
  • 基本未用。数据页和索引页,此字段总是 4 ;其他类型页(除了 PFS 页)该字段总是为 0 。如果一个 PFS 页的 m_typeFlagBits 为 1 ,表示 PFS 页映射的 PFS 区间中的至少有一页中有至少一个幽灵记录。
  • m_level
  • 这表示页在 B 树上的层。
  • 叶节点是 0 层,每向上加一层增加 1 ,直到根节点(即 B 树的最高点)。
  • 在 SQL SERVER 2000 中,一个聚集索引的叶节点(数据页)是 0 ,它的上面一层(索引页)也是 0 ,,然后才向上增加,直到根节点。所以在 SQL SERVER 2000 中为了判断一个页是否是叶节点,你需要查看 m_type 和 m_level 两个字段。
  • 除了索引页外所有其他类型的页,其层次总是为 0 。
  • m_flagBits
  • 这包含了一些用来描述页的不同的标志。比如, 0x200 表示页上面有校验和(就像我们的例子); 0x100 表示页上面有残损页保护。
  • 一些位在 SQL SERVER 2005 中不再使用。
  • m_objId
  • m_indexId
  • 在 SQL SERVER 2000 中,这些 ID 表示本页所分配给的实际的关系对象和索引的 ID 。在 SQL SERVER 2005 中,不再是这样了。分配元数据全部改了,所以这些字段不再表示 ID 了而是表示本页所属的分配单元了。
  • m_prevPage
  • m_nextPage
  • 这是 B 树上同一层中的前一页和后一页的指针。这些字段都是 6 个字节的页 ID.
  • 索引的每层上的页都用一个双向链表按索引的逻辑顺序(就是定义的索引键)链接起来。因为存在碎片,所以指针指向的页没有必要跟当前页物理上相邻。
  • B 树上一层最左面的页的 m_prevpage 为 NULL; 最右面的页的 m_nextpage 为 NULL.
  • 堆或者只有一页的索引中,所有页的这两个指针都是 NULL.
  • pminlen
  • 页中记录的定长部分的大小。
  • m_slotCnt
  • 页中记录的个数。
  • m_freeCnt
  • 页中有多少字节的可用空间。
  • m_freeData
  • 从页开始到最后一个 记录结尾的下一字节的偏移值。如果它前面也有可用空间也没有关系。
  • m_reservedCnt
  • 由活动事务保留的可用空间的字节数。这可以防止用光所有的可用空间,以保证事务能正确回滚。改变这个值有一套复杂的算法。
  • m_lsn
  • 最后一次修改本页的日志的 LSN.
  • m_xactReserved
  • 最后一次加到 m_reservedCnt 上的数目。
  • m_xdesId
  • 最近一次加到 m_reserverdCnt 上的事务的内部 ID.
  • m_ghostRecCnt
  • 页中幽灵记录的数目。
  • m_tornBits
  • 本字段或者是页的校验和或者是残损页保护中被替换的位。这是依赖于本数据库到底是用哪种保护方式。
  • 网友评论
    <