Page结构
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结构的更多相关文章
- 查看Page结构
SQL Server存储数据的基本单元是Page,每一个Page的大小是8KB,数据文件是由Page构成的.在同一个数据库上,每一个Page都有一个唯一的资源标识,标识符由三部分组成:db_id,fi ...
- Operating System Memory Management、Page Fault Exception、Cache Replacement Strategy Learning、LRU Algorithm
目录 . 引言 . 页表 . 结构化内存管理 . 物理内存的管理 . SLAB分配器 . 处理器高速缓存和TLB控制 . 内存管理的概念 . 内存覆盖与内存交换 . 内存连续分配管理方式 . 内存非连 ...
- 【转】Linux Page Cache的工作原理
1 .前言 自从诞生以来,Linux 就被不断完善和普及,目前它已经成为主流通用操作系统之一,使用得非常广泛,它与Windows.UNIX 一起占据了操作系统领域几乎所有的市场份额.特别是在高性能计算 ...
- 磁盘文件I/O,SSD结构,局部性原理 笔记
磁盘文件I/O过程 进程向内核发起read scene.dat请求: 内核根据inode获取对应该进程的address space,在address space查找page_cache,如果没有找到, ...
- page_address()函数分析--如何通过page取得虚拟地址
由于X86平台上面,内存是划分为低端内存和高端内存的,所以在两个区域内的page查找对应的虚拟地址是不一样的. 一. x86上关于page_address()函数的定义 在include/linux/ ...
- 复合页( Compound Page )
复合页(Compound Page)就是将物理上连续的两个或多个页看成一个 独立的大页,它能够用来创建hugetlbfs中使用的大页(hugepage). 也能够用来创建透明大页( ...
- Linux内存描述之内存页面page–Linux内存管理(四)
服务器体系与共享存储器架构 日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDriver ...
- 【原创】(十)Linux内存管理 - zoned page frame allocator - 5
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- Postgresql物理存储结构
Postgresql目前不支持使用裸设备和块设备. Postgresql的属于 Relation:表示表或索引. Tuple:表示表中的行. Page:表示在磁盘中的数据块. Buffer:表示在内存 ...
随机推荐
- SQL Server 高并发Insert数据解析,实践
在现实的生产环境中,有可能遇到高并发insert的应用.在此应用时由于堆表(Heap)和聚集表的结构不同导致在高并发的情形下insert效率不尽相同.接下来我会简单的以测试用例来简要说明.并举例说明如 ...
- python2与python3的区别(持续更新)
1,print(打印),python2不换行可以使用逗号,python3不换行使用end='' python2版本: print 'a' 输出一个字符串 print a 输出一个变量 print 'a ...
- 处理 Windows 虚拟机的计划内维护通知
Azure 定期执行更新,以提高虚拟机的主机基础结构的可靠性.性能及安全性. 更新包括如下更改:修补托管环境或升级以及解除硬件授权. 大多数此类更新在执行时不会影响托管的虚拟机. 但是,也会存在更新产 ...
- 注意Sqlserver中使用with(nolock)后实际上还是会加架构锁,只是不对要查询的数据加S锁而已(转载)
开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK)其实是表提示(table_hint)中的一种.它等同于 READUNCOMMITTED . 具体的功能作用如下所示(摘 ...
- Sql Server与.Net(C#)中星期值对比
最近发现Sql Server与.Net(C#)中星期值居然不匹配,倒不知道依哪一个了. 1.Sql Server declare @date datetime; set @date = '2017-0 ...
- 简单实现MySQL数据库的日志审计
时间 2018-12-23 08:01:11 FreeBuf 原文 https://www.freebuf.com/articles/es/192062.html 主题 MySQL 0×0 背景 ...
- js经典应用
一.js字符串转数字: 1.parseInt()和parseFloat()两个转换函数: 2.强制类型转换,Number(value)——把给定的值转换成数字(可以是整数或浮点数): 3.利用js变量 ...
- 使用C#删除一个字符串数组中的空字符串
C#中要如何才能删除一个字符串数组中的空字符串呢?随着微软对C#不断发展和更新,C#中对于数组操作的方式也变得越来越多样化.以往要实现过滤数组中的空字符串,都是需要实行循环的方式来排除和过滤.C#3. ...
- Balanced Search Trees
平衡搜索树 前面介绍的二叉搜索树在最坏情况下的性能还是很糟糕,而且我们不能控制操作的顺序,有时根本就不是随机的,我们希望找到有更好性能保证的算法. 2-3 search trees 于是先来了解下 2 ...
- python 使用csv 文件写入 出现多余空行数据解决方案
因为csv.writerow() 方法会造成读取时每条数据后多一条空数据 解决方案如下: 分为两种情况 python2 和 python3 先说python2版本 with open('xxx.csv ...