SQL Server存储数据的基本单元是Page,每一个Page的大小是8KB,数据文件是由Page构成的。在同一个数据库上,每一个Page都有一个唯一的资源标识,标识符由三部分组成:db_id,file_id,page_id,例如,15:1:8733,15是数据库的ID,1是数据文件的ID,8733是Page的编号,Page的编号从0依次递增。8个连续的Page组成一个区(Extent),数据文件中已分配(Allocated)的空间被分割成区的整数倍。一次磁盘IO操作作用于Page级别,而空间分配的最小单元是区。

一,Page的类型

Page是用于存储数据的,不同类型的Page存储的数据是不同的,Page的结构也是不同的。有些Page是用于存储数据的,叫做Data Page,有些Page是用于存储索引结构中的中间节点的,叫做Index Page,有些Page是SQL Server存储引擎使用的,用于管理Page的,叫做系统页。Page类型和存储的数据类型如下表所示:

Page type Contents
Data Data rows with all data, except text, ntext, image, nvarchar(max), varchar(max), varbinary(max), and xml data, when text in row is set to ON.
Index Index entries.
Text/Image Large object data types: (text, ntext, image, nvarchar(max), varchar(max), varbinary(max), and xml data)
Variable length columns when the data row exceeds 8 KB: (varchar, nvarchar, varbinary, and sql_variant)
Global Allocation Map, Shared Global Allocation Map Information about whether extents are allocated.
Page Free Space (PFS) Information about page allocation and free space available on pages.
Index Allocation Map Information about extents used by a table or index per allocation unit.
Bulk Changed Map Information about extents modified by bulk operations since the last BACKUP LOG statement per allocation unit.
Differential Changed Map Information about extents that have changed since the last BACKUP DATABASE statement per allocation unit.

日志文件没有Page结构,它是由一系列的日志记录构成的。本文关注的是Data Page和Index Page,跟数据表有关。

二,数据Page的结构

每一个Page都由头部(Header),内容(Content)和行偏移量(Offset)组成,也叫做Slot,头部是在Page的开始处,占用96Bytes,用于存储Page的编号,Page的类型,分配单元(Allocation Unit)等系统信息。注:在单个Page中最多存储8060Bytes的数据,也就是一行要想存储到一个Page中,该行包含的字节最大不能超过8060Bytes,超过8060Bytes的行会被拆分。

数据行存储在Page Header之后,数据行在Page中的物理存储是无序的,行的逻辑顺序是由行偏移(Row Offset)确定的,行偏移存储在Page的末尾,每一个行偏移是一个Slot,占用2B。行偏移连续排列在Page的末尾,称作槽数组(Slot Array)。行偏移以倒序方式存储行的偏移量,这意味着,从Page末尾向Page 开头计数,第一行的偏移量存储在Page的末尾Slot中,第二行的偏移量存储在Page末尾的第二个Slot中。

三,DBCC PAGE()命令

PAGE中存储的数据页或索引页,可以使用非正式的命令来查看:

DBCC PAGE(['database name'|database id], file_id, page_number, print_option = [0|1|2|3] )

参数注释:

  • database_id:page所在的数据库
  • file_id:数据库文件的ID;
  • page_number:该Page在文件中的编号;
  • print_option是指打印信息的详细程度,默认值是0,只打印Page Header。

参数Print_option的有效值是0、1、2、3,表示显示信息的详细程度:

  • 0 – print just the page header
  • 1 – page header plus per-row hex dumps and a dump of the page slot array (unless its a page that doesn’t have one, like allocation bitmaps)
  • 2 – page header plus whole page hex dump
  • 3 – page header plus detailed per-row interpretation

四,查看Page头部信息

Page头部信息存储的是Page的系统信息,例如,查看资源标识符:15:1:8777733 Page的头部信息:

dbcc traceon(3604)
dbcc page(15,1,8777733)

在我的数据库中,该Page的头部信息(移除Buffer的数据)如下所示,

PAGE: (1:8777733)

PAGE HEADER:
Page @0x0000005188B02000 m_pageId = (1:8777733) m_headerVersion = 1 m_type = 1
m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x220
m_objId (AllocUnitId.idObj) = 28503 m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057595905900544
Metadata: PartitionId = 72057594059423744 Metadata: IndexId = 1
Metadata: ObjectId = 1029578706 m_prevPage = (1:8777732) m_nextPage = (1:8777734)
pminlen = 16 m_slotCnt = 2 m_freeCnt = 4513
m_freeData = 3675 m_reservedCnt = 0 m_lsn = (1212327:16:558)
m_xactReserved = 0 m_xdesId = (0:799026688) m_ghostRecCnt = 0
m_tornBits = -1518328013 DB Frag ID = 1 Allocation Status
GAM (1:8690944) = ALLOCATED SGAM (1:8690945) = NOT ALLOCATED
PFS (1:8775480) = 0x40 ALLOCATED 0_PCT_FULL DIFF (1:8690950) = CHANGED
ML (1:8690951) = NOT MIN_LOGGED  

Page 头部返回的各个字段的含义:

1,Page的编号

m_pageId = (1:8777733),该Page所在的File ID 和Page ID

2,Page的类型

m_type = 1,Page的类型,常见的类型是数据页和索引页:

  • 1 – data page,用于表示:堆表或聚集索引的叶子节点
  • 2 – index page,用于表示:聚集索引的中间节点或者非聚集索引中所有级别的节点

其他Page类型(系统页是管理Page的Page,例如,GAM,IAM等)如下

  • 3 – text mix page,4 – text tree page,用于存储类型为文本的大对象数据
  • 7 – sort page,用于存储排序操作的中间数据结果
  • 8 – GAM page,用于存储全局分配映射数据GAM(Global Allocation Map),每一个数据文件被分割成4GB的空间块(Chunk),每一个Chunk都对应一个GAM数据页,GAM数据页出现在数据文件特定的位置处,一个bit映射当前Chunk中的一个区。
  • 9 – SGAM page,用于存储SGAM页(Shared GAM)
  • 10 – IAM page,用于存储IAM页(Index Allocation Map)
  • 11 – PFS page,用于存储PFS页(Page Free Space)
  • 13 – boot page,用于存储数据库的信息,只有一个Page,Page的标识符是:db_id:1:9,
  • 15 – file header page,存储数据文件的数据,数据库的每一个文件都有一个,Page的编号是0。
  • 16 – diff map page,存储差异备份的映射,表示从上一次完整备份之后,该区的数据是否修改过。
  • 17 – ML map page,表示从上一次备份之后,在大容量日志(bulk-Logged)操作期间,该区的数据是否被修改过,This is what allows you to switch to bulk-logged mode for bulk-loads and index rebuilds without worrying about breaking a backup chain.
  • 18 – a page that’s be deallocated by DBCC CHECKDB during a repair operation.
  • 19 – the temporary page that ALTER INDEX … REORGANIZE (or DBCC INDEXDEFRAG) uses when working on an index.
  • 20 – a page pre-allocated as part of a bulk load operation, which will eventually be formatted as a ‘real’ page.

3,Page在索引中的级数

数据页在索引中的索引级数,m_level=0,表示处于Leaf Level。

  • 对于堆表(Heap),m_level=0表示的是Data Page;
  • 对于聚集索引,m_level=0表示的是Data Page;
  • 对于非聚集索引,m_level=0表示的是叶子节点

4, Page的元数据

Page的元数据十分重要,不仅能够查看处Page所在的Object,甚至能够查看该Page所在的分配单元和分区ID,在死锁进行故障排除时十分有用

  • Metadata: AllocUnitId =72057595905900544,该Page所在的分配单元ID(allocation_unit_id)
  • Metadata: PartitionId =72057594059423744,该Page所在的分区的分区ID(partition_id)
  • Metadata: IndexId = 1,该Page所在的索引ID
  • Metadata: ObjectId = 1029578706,用于表示Page所属对象的object_id

5,page的链指针

由于数据表的Page并不是单独存在的,而是通过双向链式结构连接在一起的,

  • m_prevPage = (1:8777732)       :用于表示前一个page (FileID : PageID)
  • m_nextPage = (1:8777734)  :用于表示下一个page (FileID:PageID)

6, 其他头部字段  

  • m_slotCnt = 2            :页面中Slot的数量,用于Page中存储的数据行数
  • m_freeCnt = 4513   :页面中剩余的空间,单位是字节,还剩83字节的空间 
  • m_reservedCnt = 0    :为活动事务保留的存储空间,单位是字节
  • m_ghostRecCnt = 0   :页面中存在的幽灵记录的总数(ghost record count)

关于Page头部的信息,可以阅读《Inside the Storage Engine: Anatomy of a page》;

五,利用Page的元数据排除死锁

Page的元数据包含分区ID,索引ID和对象ID,用户可以使用这些元数据,分析死锁产生的原因。系统追踪到产生死锁的资源,可能是一个Page的资源标识符,如果能够确认发生死锁是由于数据表或索引的分区不合理导致的,那么可以重新设置分区列,或者设置分区边界值,把单个分区拆分成多个分区,这样就能把竞争的临界资源分配到不同的分区中,避免查询请求对资源的竞争,进而减少死锁的发生。

  • Metadata: PartitionId ,该Page所在的分区的分区ID(partition_id);
  • Metadata: IndexId ,该Page所在索引ID;
  • Metadata: ObjectId,用于表示对象的object_id;

参考文档:

Pages and Extents Architecture Guide

Using DBCC PAGE to Examine SQL Server Table and Index Data

Inside the Storage Engine: How are allocation unit IDs calculated?

Inside the Storage Engine: Anatomy of a page

笔记17 DBCC IND()非常详细解释加dbcc page([GPOSDB],1,119,3)非常详细解释 2013-1-20

查看Page结构的更多相关文章

  1. Page结构

    SQL Server存储数据的基本单元是Page,每一个Page的大小是8KB,数据文件是由Page构成的.在同一个数据库上,每一个Page都有一个唯一的资源标识,标识符由三部分组成:db_id,fi ...

  2. SOME:收缩数据库日志文件,查看表数据量和空间占用,查看表结构索引修改时间

    ---收缩数据库日志文件 USE [master]ALTER DATABASE yourdatabasename SET RECOVERY SIMPLE WITH NO_WAITALTER DATAB ...

  3. sp_help 快速查看表结构、视图信息

    sp_helptext: 是MS SQL Server的一个系统存储过程,可以通过它来查看存储过程或者视图.函数源码 示例:sp_helptext viewName (viewName  即要查询的存 ...

  4. Sql语句查看表结构

    快速查看表对的就说明,及表字段描述及字段类型 --表描述 SELECT tbs.name 表名,ds.value 描述 FROM sys.extended_properties ds LEFT JOI ...

  5. MySQL 查看表结构

    mysql查看表结构命令,如下: desc 表名; show columns from 表名; describe 表名; show create table 表名; use information_s ...

  6. mysql查看表结构命令

    mysql查看表结构命令 mysql查看表结构命令,如下: desc 表名;show columns from 表名;describe 表名;show create table 表名; use inf ...

  7. 查看表结构命令(mysql和oracle)

    MySQL查看表结构SQL语句 = mysql查看表结构命令,如下: desc 表名; show columns from 表名; describe 表名; show create table 表名; ...

  8. mysql查看表结构2种方式对比

    1.desc t_bookType; 2.show create table t_bookType; 相信大部分人还是喜欢第一种查看表结构方式.

  9. SQL Server--------SQL Server常用(查看注释,新增注释,生成实体,查看表结构信息,case when...)

    --新增字段: ALTER TABLE line_info ADD line_remark NVARCHAR(MAX) DEFAULT ''  EXECUTE sp_addextendedproper ...

随机推荐

  1. 多线程之Map:Hashtable HashMap 以及ConcurrentHashMap

    1.Map体系参考:http://java.chinaitlab.com/line/914247.htmlHashtable是JDK 5之前Map唯一线程安全的内置实现(Collections.syn ...

  2. 损失函数&经验函数

    损失函数:度量模型一次预测的好坏 经验函数:度量模型平均意义下的预测好坏 输出预测值F(x)与实际值Y可能不一致也可能一致,损失函数(Loss function)可以度量一次预测,记作L(Y,F(x) ...

  3. 关于WSL(Windows上的Linux子系统)的介绍

    WSL,Windows Subsystem for Linux,就是之前的Bash on [Ubuntu on] Windows(嗯,微软改名部KPI++ 首先要说一句,其实Windows 10在一周 ...

  4. 修改Oracle【12C】字符集

    select userenv('language') from dual; //查看系统字符集编码 select * from nls_database_parameters where parame ...

  5. SVN.服务器迁移方法

    SVN项目, 源服务器  : 10.10.13.48 目标服务器: 10.10.13.129 要把SVN项目从.48上迁移到.129上. 做法: 准备: 版本库:vos 源服务器  : 10.10.1 ...

  6. swift 上的 lazy

    lazy顾名思义就是慢吞吞的,万非得一就不动. 那么一个变量也是如此,只有你第一次使用的时候才进去加载.所有又称为延迟加载,需要的时候才加载. ========= 这样做的好处: 1. 模块化,把对象 ...

  7. lua State加载部分库

    lua State加载部分库 在lua中,通常我们用luaL_openlibs(L)加载所有的lub标准库,但是有时候我们想只加载部分,有没有什么好的办法呢?在luaproc看到如下办法: stati ...

  8. 从成本角度看Java微服务

    近年来,微服务因其良好的灵活性和伸缩性等特点备受追捧,很多公司开始采用微服务架构或将已有的单体系统改造成微服务.IBM也于近日开源了轻量级Java微服务应用服务器 Open Liberty .但是采用 ...

  9. 小米Java程序员第二轮面试10个问题,你是否会被刷掉?

    近日,开发者头条上分享了一篇"小米java第二轮面经",有很多的java程序员表示非常有兴趣. 下面l就和各位分享小米java第二轮面经(华为java工程师笔试面试题可以看文章某尾 ...

  10. JavaScript系列-----对象基于哈希存储(<Key,Value>之Value篇) (3)

    JavaScript系列-----Objectj基于哈希存储<Key,Value>之Value 1.问题提出 在JavaScript系列-----Object之基于Hash<Key, ...