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. Operating System Memory Management、Page Fault Exception、Cache Replacement Strategy Learning、LRU Algorithm

    目录 . 引言 . 页表 . 结构化内存管理 . 物理内存的管理 . SLAB分配器 . 处理器高速缓存和TLB控制 . 内存管理的概念 . 内存覆盖与内存交换 . 内存连续分配管理方式 . 内存非连 ...

  3. 【转】Linux Page Cache的工作原理

    1 .前言 自从诞生以来,Linux 就被不断完善和普及,目前它已经成为主流通用操作系统之一,使用得非常广泛,它与Windows.UNIX 一起占据了操作系统领域几乎所有的市场份额.特别是在高性能计算 ...

  4. 磁盘文件I/O,SSD结构,局部性原理 笔记

    磁盘文件I/O过程 进程向内核发起read scene.dat请求: 内核根据inode获取对应该进程的address space,在address space查找page_cache,如果没有找到, ...

  5. page_address()函数分析--如何通过page取得虚拟地址

    由于X86平台上面,内存是划分为低端内存和高端内存的,所以在两个区域内的page查找对应的虚拟地址是不一样的. 一. x86上关于page_address()函数的定义 在include/linux/ ...

  6. 复合页( Compound Page )

    复合页(Compound Page)就是将物理上连续的两个或多个页看成一个      独立的大页,它能够用来创建hugetlbfs中使用的大页(hugepage).      也能够用来创建透明大页( ...

  7. Linux内存描述之内存页面page–Linux内存管理(四)

    服务器体系与共享存储器架构 日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDriver ...

  8. 【原创】(十)Linux内存管理 - zoned page frame allocator - 5

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  9. Postgresql物理存储结构

    Postgresql目前不支持使用裸设备和块设备. Postgresql的属于 Relation:表示表或索引. Tuple:表示表中的行. Page:表示在磁盘中的数据块. Buffer:表示在内存 ...

随机推荐

  1. Oracle EBS OPM complete batch

    --complete_batch --created by jenrry SET serveroutput on DECLARE x_return_status VARCHAR2 (1); l_exc ...

  2. Oracle EBS 贷项通知单核销

    SELECT cm.trx_number ,fnd_flex_ext.get_segs('SQLGL', 'GL#', gcc.chart_of_accounts_id, ad.code_combin ...

  3. "添加"模态框中某些数据不被清空

    描述:一般情况下,“添加”的模态框弹出够,其中的输入框等为空,若是此中有某些数据是取自其他页面,不应被清空的,我们应当在html中添加以下内容.   解决方案:在form标签中添加“ preserve ...

  4. [原创]使MySQL注释语句在后台能够输出的方法

    开启general log或slow log的时候,前端发出的sql语句中的注释都别屏蔽掉了. 本意加注释我们想通过注释来快速知道sql是由哪个业务模块发出的.这点对dba和研发很有帮助. 一种变通的 ...

  5. [Python_7] Python Socket 编程

    0. 说明 Python Socket 编程 1. TCP 协议 [TCP Server] 通过 netstat -ano 查看端口是否开启 # -*-coding:utf-8-*- "&q ...

  6. tplink-ssh登录

    同步发表:https://www.eatm.app/archives/395.html 备份配置信息 开启SSH #修改文件userconfig/etc/config/dropbear, #查看opt ...

  7. python3: 数字日期和时间(1)

    ---恢复内容开始--- 1. 数字的四舍五入 Q: 你想对浮点数执行指定精度的舍入运算 A: 简单的使用内置的round(value, ndigits)函数即可. >>> roun ...

  8. beta冲刺————第五天(5/5=1)

    今天的主要内容是前后端的对接: 通过前几天的对接,我们发现后端传给前端内容是可以很完美的显示出来的,说明文章格式以及一些默认规则都是OK的. 然后就是前端从云服务器上面接受到文章的具体内容,在这一个环 ...

  9. 图解:图形下控制台中weblogic9.2多池配置为oracle集群RAC

    update: 这个东西如果配置不顺利的话:应用请求数据库的时候,会打印类似这样的错误: :open connection err Pool connect failed : weblogic.com ...

  10. 用BCP从SQL Server 数据库中导出Excel文件

    BCP(Bulk Copy Program)是一种简单高效的数据传输方式在SQL Server中,其他数据传输方式还有SSIS和DTS. 这个程序的主要功能是从数据库中查询Job中指定step的执行信 ...