菜单

4166m金沙2008存储结构之GAM,理解数据页结构

2019年9月16日 - 数据网络
4166m金沙2008存储结构之GAM,理解数据页结构

数据页是包含已添加到数据库表中的用户数据的结构。

我们都很清楚SQL Server用8KB
的页来存储数据,并且在SQL Server里磁盘 I/O 操作在页级执行。也就是说,SQL
Server
读取或写入所有数据页。页有不同的类型,像数据页,GAM,SGAM等。在这文章里,让我们一起来理解下数据页结构。

4166m金沙,【IT168专稿】谈到GAM和SGAM,我们不得不从数据库的页和区说起。一个数据库由用户定义的空间构成,这些空间用来永久存储用户对象,例如数据库管理信息、表和索引。这些空间被分配在一个或多个操作系统文件中。

如前所述, 数据页有三种, 每个都以不同的格式存储数据。

SQL
Server把数据记录存在数据页(Data
Page)里。数据记录是堆表里、聚集索引里叶子节点的行。

  当我们创建一个数据库的时候,例如以缺省的方式CREATE DATABASE
TESTDB,SQLServer自动帮我们创建好如下两个数据库文件。

SQL server 有行内数据页、行溢出数据页和 LOB 数据页。

数据页由3个部分组成。页头(标头),数据区(数据行和可用空间)及行偏移数组。

4166m金沙 1
 

与 SQL server 中的所有其他类型的页一样, 数据页的大小固定为 8 KB
或8192字节。

4166m金沙 2

  这两个数据文件是实实在在的操作系统文件,其中一个是叫行数据文件,用来存储数据库的各种对象,另外一个是日志文件,从来记录数据变化的过程。

它们由三主要组件组成: 页面页眉、数据行和行偏移量数组, 如图6-4 所示。

在我们讨论在SQL
Server里,数据页内部结构具体是什么样之前,我们来创建一个表并插入一些记录。

  从逻辑角度而言,数据库的最小存储单位为页即8kb。

4166m金沙 3

 

  数据库被分成若干逻辑页面(每个页面8KB),并且在每个文件中,所有页面都被连续地从0到x编号,其中x是由文件的大小决定的。我们可以通过指定一个数据库ID、一个文件ID、一个页码来引用任何一个数据页。每个数据页则用来存储表和索引,以及相关的数据库管理信息。

 

 1 USE [InternalStorageFormat]
 2 GO
 3 
 4 IF EXISTS ( SELECT  *
 5             FROM    sysobjects
 6             WHERE   id = OBJECT_ID(N'[dbo].[Customers]')
 7                     AND OBJECTPROPERTY(id, N'IsUserTable') = 1 )
 8     DROP TABLE dbo.Customers
 9 
10 CREATE TABLE Customers
11 (
12    FirstName CHAR(50) NOT NULL,
13    LastName CHAR(50) NOT NULL,
14    Address CHAR(100) NOT NULL,
15    ZipCode CHAR(5) NOT NULL,
16    Rating INT NOT NULL,
17    ModifiedDate DATETIME NOT NULL,
18 )
19 GO
20 
21 
22 INSERT INTO dbo.Customers
23         ( FirstName ,
24           LastName ,
25           Address ,
26           ZipCode ,
27           Rating ,
28           ModifiedDate
29         )

30 VALUES  ( 'Woody' , -- FirstName - char(50)
31           'Tu' , -- LastName - char(50)
32           'ZUOQIAO YOUXI TOWN LINHAI CITY' , -- Address - char(50)
33           '0000' , -- ZipCode - char(5)
34           1 , -- Rating - int
35           '2015-05-07 10:09:51'  -- ModifiedDate - datetime
36         )
37         go 2

  我们顺着上面数据文件的路径可以找到该文件,观察一下新建的数据文件的大小为:

页标题

现在我们要找出SQL
Server给这个表分配的页有哪些,这个就要用到非文档的命令DBCC
IND。
它的语法如下:

  2.18 MB (2,293,760 字节)=2,293,760b/8kb=280个页面=35个区

 

DBCC IND
命令用于查询一个存储对象的内部存储结构信息,该命令有4个参数,
前3个参数必须指定。语法如下:
DBCC IND ( { ‘dbname’ | dbid }, { ‘objname’ | objid },{ nonclustered
indid | 1 | 0 | -1 | -2 } [, partition_number] )
第一个参数是数据库名或数据库ID。
第二个参数是数据库中的对象名或对象ID,对象可以是表或者索引视图。
第三个参数是一个非聚集索引ID或者 1, 0, 1, or 2. 值的含义:
 0: 只显示对象的in-row data页和 in-row IAM 页。
 1: 显示对象的全部页, 包含IAM 页, in-row数据页, LOB 数据页row-overflow
数据页 . 如果请求的对象含有聚集所以则索引页也包括。
 -1: 显示全部IAM页,数据页, 索引页 也包括 LOB 和row-overflow 数据页。
 -2: 显示全部IAM页。
 Nonclustered index ID:显示索引的全部 IAM页, data页和索引页,包含LOB和
row-overflow数据页。
为了兼容sql server
2000,第四个参数是可选的,该参数用于指定一个分区号.如果不给定值或者给定0,
则显示全部分区数据。
和DBCC PAGE不同的是, SQL Server运行DBCC
IND不需要开启3604跟踪标志.

  数据库进行空间管理的最小单位为区(extents)。

如图6-4 所示, 页标题占据每个数据页的前96个字节
(为数据、行开销和行偏移保留8096个字节)。表6-5
列出了检查页标题时显示的一些信息。

我们来执行下列的命令:

  一个区由8个逻辑上连续的页面组成(64KB的空间)。为了能够更有效地分配空间,SQL
Server 2008不会为少量的数据向数据表分配整区的空间。SQL Server
2008有两种类型的区。

4166m金沙 4

1 DBCC IND('InternalStorageFormat','Customers',-1)

  统一类型的区
这些区为单个对象所有,区中所有的8个数据页只能被所属对象使用。

 

SQL
Server会给我们如下的输出结果:
4166m金沙 5

  混合类型的区 这些区能为最多8个对象共享。

行内数据的数据行

可以看到有2条记录,一条记录为页面类型(PageType)为10的页和一条记录为页面类型(PageType)为1的页。页面类型(PageType)10是IAM页,页面类型(PageType)1是数据页,它的页ID是79.

  SQL
Server为新的表或索引从混合类型的区中分配页面。当该表或索引增长到8个页面时,以后所有的分配都使用统一类型的区。

 

关于数据库页类型如下所示:

  当一张表或一个索引需要更多的空间时,SQL
Server需要找到能够用来分配的空间。如果该表或索引整体仍然少于8个页面,SQL
Server必须找到能够用来分配的混合类型区构成的空间。如果表或索引有8个页面或更大,SQL
Server必须找到一个自由的统一类型的区。

页标题后面是存储表实际数据行的区域。单个数据行的最大大小为8060字节的行内数据。

  SQL
Server使用两种特殊类型的页面来记录哪些区已经被分配出去了,哪些类型(混合类型或统一类型)的区可供使用:

行还可以在单独的页上存储行溢出和 LOB 数据。

现在我们来看看79号类型为1的数据页里存放的数据,这个就要用到DBCC
PAGE命令,它的语法如下:

  全局分配映射(Global Allocation Map,GAM)页面
这些页面记录了哪些区已经被分配并用作何种用途。一个GAM页面在它所覆盖空间里针对每一个区都有一个数据位。如果数据位为0,那么对应的区正在使用;如果该数据位为1,那么该区为自由区。一个GAM页面除了页面头部和其他一些需要记入的开销大概有8
000字节或者说64 000位空间可用,所以每个GAM页面可以覆盖64
000个区,也就是大约4GB的数据。这意味着一个文件的每4GB空间对应一个GAM页面。

在给定页上存储的行数根据表结构和存储的数据而变化。

dbcc page
命令读取数据页结构的命令DBCC Page。
该命令为非文档化的命令,具体如下:
  DBCC Page ({dbid|dbname},filenum,pagenum[,printopt])
  具体参数描述如下:
  dbid 包含页面的数据库ID
  dbname 包含页面的数据库的名称
  filenum 包含页面的文件编号
  pagenum 文件内的页面
  printopt 可选的输出选项;选用其中一个值:
  0:默认值,输出缓冲区的标题和页面标题
  1:输出缓冲区的标题、页面标题(分别输出每一行),以及行偏移量表
  2:输出缓冲区的标题、页面标题(整体输出页面),以及行偏移量表
  3:输出缓冲区的标题、页面标题(分别输出每一行),以及行偏移量表;每一行
  后跟分别列出的它的列值
  要想看到这些输出的结果,还需要设置DBCC TRACEON(3604)。

  共享全局分配映射(Shared Global Allocation Map,SGAM)页面
这些页面记录了哪些区当前被用作混合类型的区,并且这些区需含有至少一个未使用的页面。就像一个GAM页面,每一个SGAM页面覆盖了大约64
000个区,也就是大约4GB的数据。一个SGAM页面在它所覆盖空间里针对每一个区都有一个数据位。如果数据位为1,那么对应的被使用的区为混合类型,并且该区有一些自由页面;如果数据位为0,那么对应的区不是一个混合类型的区,或者虽然是一个混合类型的区,但是所有的页面都已被使用了。

具有所有固定长度列的表始终可以存储每页相同的行数;

我们来执行下列的命令:

  表4-2显示了基于每一个区当前的使用情况,在GAM和SGAM中该区所对应的比特位模式。

可变长度行可以根据输入数据的实际长度, 存储尽可能多的行。

1 DBCC TRACEON(3604)
2 DBCC PAGE(InternalStorageFormat,1,79,3)
3 GO    
区的当前使用情况 GAM比特位设置 SGAM比特位设置
自由,未使用 1 0
统一类型或已全部使用的混合区 0 0
含有自由页面的混合区 0 1

保持行长更短可以使更多行适合页面, 从而减少 i/o
并增加所需数据在缓存中的可能。

SQL
Server会给我们包含4个部分的输出。第1部分是BUFFER,里面是一些内存分配信息,对此我们没多少兴趣。下一部分是固定96
bytes大小的页头(page header),页头(page
header)会类似如下显示:

  如果SQL
Server需要找到一个新的完全没有使用的区,那么它可以使用任何一个在GAM页面中对应的比特位值为1的区。如果SQL
Server需要找到一个有着可用空间(有一个或多个自由页面)的混合类型的区,那么它可以寻找一个对应的GAM中的值为0、SGAM中的值为1的区。如果不存在有可用空间的混合类型的区,SQL
Server会使用GAM页面来寻找一个全新的区并将其分配为混合类型的区,然后使用该区中的一页。如果根本没有自由区,那么这个文件已经满了。

 

4166m金沙 6

第0页 第1页 第2页 第3页 第4页 第5页 第6页 第7页
m_type=15 m_type=11 m_type=8 m_type=9 m_type=0 m_type=0 m_type=16 m_type=17
头文件页 PFS页 GAM页 SGAM页 保留页 保留页 DCM页 BCM页

行偏移量数组

页头相关字段的含义:

  SQL
Server能够迅速地锁定一个文件中的GAM页面,因为它总是位于任何数据库文件的第三页上(页码为2)。SGAM页面是在第四页上(页码为3)。下一个GAM页面出现在第一个GAM页面(页码为2)以后的每511
230个页面中,并且下一个SGAM页面出现在第一个SGAM页面(页码为3)以后的每511
230个页面中。每一个数据库文件的页码为0的页面是文件头页面,并且每个文件仅有一页。页码0是头文件页,页码1是页面自由空间页(Page
Free Space,PFS)。

 

  在SQLServer2008的每一个数据库中的前八页顺序都是固定的。

行偏移量数组是2字节项的块, 每个条目表示相应数据行开始的页面上的偏移量。

再来看下页面相关分配情况:

  除了第9页为数据库的BOOT页以外,从第8页到第173页为SQLServer2008内部系统表的相关存储信息,然后从第174页到第279页为未分配页面。因为第一页从0开始,所以刚好280页,即和我们看到的数据库数据文件的大小完全相等。

每行在这个数组中都有一个2字节的条目 (正如前面所讨论的,
当您阅读每行所需的10个开销字节时)。

 4166m金沙 7

第8页

虽然这些字节没有存储在数据行中, 但它们确实会影响适合页面的行数。

第8页

 

接下来就是用于存放实际数据的槽(slot),每条记录存放一个槽(slot)里。0号槽在页里拥有第1条数据,1号槽拥有第2条数据,以此类推。通过下面的图片,你可以看到我们记录大小是224
bytes,217 bytes(50+50+100+5+4+8) 的定长和7 bytes
的系统行开销。

第8页

行偏移量数组指示页上行的逻辑顺序。

4166m金沙 8

第N页

例如, 如果表具有聚集索引, SQL server 将按聚集索引键的顺序存储这些行。

页的最后一部分是行偏移数组表,我们可以用参数为1的DBCC
PAGE命令来,在输出信息的底部获得。

第173页

这并不意味着行按聚集索引键的顺序物理地存储在页面上。

执行如下的命令:

第279页

相反, 偏移量数组中的插槽0引用聚集索引键顺序中的第一行, 插槽1引用第二行,
依此类推。

1 DBCC TRACEON(3604)
2 DBCC PAGE(InternalStorageFormat,1,79,3)
3 GO    

m_type=1

正如您在检查实际页面时所看到的那样,
这些行的物理位置可以位于页面的任何位置。

SQL
Server在输出信息的底部,给我们如下的信息:

m_type=13

 

4166m金沙 9

m_type in (1,2,10)

查看数据页

这个行偏移表,应该从下往上读。每条槽条目是一个2
bytes长的指针指向页里槽偏移量。这里我们插入了2条记录,所以表里有2个槽条目。第1条记录指向第96
bytes,刚好在页头后。这个行偏移表可以帮助我们管理页面的记录。在页里的行偏移表里,每条记录需要2
bytes的大小来存储。于此类似,在堆表上建立的非聚集索引,每个非聚集索引行里都包含一个物理指针映射回堆表里的行记录。这个物理指针是[文件号:页号:槽号](file:page:solt)的结构,因此在读取页的时候,可以找到堆表里的对应行,再通过行偏移表里槽号里的偏移量,就可以在页里读取到对应的行记录。如果我们要修改页中间的记录,我们并不一定需要重组整个页,我们只要修改偏移表里偏移量即可。

N/A

 

4166m金沙 10

Data页

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图