DBCC IND&&DBCC PAGE
1.命令
DBCC IND ( { ‘dbname’ | dbid }, { ‘objname’ | objid },{ nonclustered indid | 1 | 0 | -1 | -2 } [, partition_number] )
-
{ ‘dbname’ | dbid } 表示数据库名或者数据库ID
-
{ ‘objname’ | objid }表示对象名或者对象ID
-
{ nonclustered indid | 1 | 0 | -1 | -2 }输出选项(数据筛选)
-2:显示指定对象的所有IAM(索引分配映射)分页子节点(相当于叶节点目录) -1:显示指定对象所有IAM(索引分配映射)、数据分页、及指定对象上全部索引的索引分页. 0:只显示指定对象的数据分页(只有数据的分页信息) 1:显示指定对象的数据分页,所有存在的LOB(大对象库)分页和行溢出页
-
[, partition_number]=>可选,为了与中的DBCC IND命令向前兼容.它指定了一个特定分区号,如果不指定,显示所有分区的信息
2.DBCC输出字段描述
Column(列) | Meaning(含义) |
---|---|
PageFID | 数据及索引所在文件ID |
PagePID | 数据及索引所在文件内的ID |
IAMFID | 索引分配映射所在文件ID AM page的IAMPID=NULL |
IAMPID | 索引分配映射所在文件的页ID AM page的IAMPID=NULL |
ObjectID | 对象ID |
IndexID | 索引类型ID,0表示堆,1表示聚集索引,2-250表示非聚集索引。一表内最大非聚集索引个数为249 |
PartitionNumber | 表或索引所在的分区号码 |
PartitionID | 包含该分页的分区ID |
iam_chain_type | 页数据类型: 包括in-row data, row-overflow data, 或 LOB dataID |
PageType | 该页所属分配单元类型;行内数据、行溢出数据或Lob数据 |
IndexLevel | 分页类型:1.数据页面;2.索引页面;3.Lob_mixed_page;4.Lob_tree_page;10.IAM页面 |
NextPageFID | 本层下一个分页所在的文件ID,同一等级上下一个索引页所在文件的ID |
NextPagePID | 本层下一个分页ID |
PrevPageFID | 本层上一个分页所在的文件ID |
PrevPagePID | 本层上一个分页ID,同一等级上的上一个索引页,通过双向链表连接起来 |
3.数据组成
首先,如上图红框所示,按照总分的结构,可以将数据分成页目录和页数据两部分,页目录(pagetype=10)内可以跟踪到所有与其相关的页数据。我们暂时称其为(数据页总分存储)
另外,如上图绿框和紫框标识,按照数据的类型可以分为4类
- 一般数据存储页(IndexID=0&&PageType=1)
- 一般数据页的大对象存储页(IndexID=0&&PageType=3)或(LOB data=LOB data)
- 聚集索引存储页(IndexID=1)==》聚集索引数量为1个
- 非聚集索引存储页==》2~250表示为非聚集索引,索引单表最大非聚集索引数为249
以上四类,每类皆对应(数据页总分存储)的数据,由此构成一个完整的表存储结构
4.数据分析
dbcc IND(DBV2_0506_2016,T_ProductLibraryDescriptions,-1)
将上图所示数据保存在某表中
select * from [dbo].[pageP] where pagetype=10
pagetype=10(相当于文件页目录)的数据部分,条目的信息在存储结构上形成了收尾相接的类似链表的结构,并且形成了一个完整的整体(有开始,有结束)。
针对于单一表格,数据内的ObjectID是同一个(即一个table对象表示一个ObjectID),,由此我们可以推测出数据库数据的存储结构==》单一表格的数据,数据被记录在不同的页上进行存储,但是然后通过IAM(索引分配映射)将数据聚集起来,形成一个区块的整体,然后再通过IAM(pagetype=10)将所有的数据汇聚成一个完整的整体
5.深入探索
我们已经看到了数据库数据存放的页了,我更想看看页里放了哪些东西》》》接下来请擦亮眼睛
Dbcc page(DBV2_0506_2016,1,12797,2)
执行上一串代码,出现了如上的问题?(不是说好的看好东西的吗?眼镜都擦好了,你给我看这个。。。)
不要方,出现上面的问题,请执行代码如下:
dbcc TRACEON(3604)
这个指定的标记就是可以将DBCC Page的结果显示在客户端,否则就显示不出来了
在这里,我们先缓一缓,先来解释下Dbcc page(DBV2_0506_2016,1,12797,2)的参数构成
dbcc page ( {‘dbname’ | dbid}, filenum, pagenum [, printopt={0|1|2|3} ])
-
{‘dbname’ | dbid}:数据库名称
-
filenum:所在文件编号
-
pagenum :页编号
-
[, printopt={0|1|2|3} ]:输出选项
-0:输出可读形式的数据页页头数据,原因是这样的,在一个数据页中,有96个字节空间来表示一个数据页头 -1:输出可读形式的数据页页头数据,并且还有槽位对应记录的十六进制内容 -2:输出整个数据页页头的十六进制数据,包括(页头,内容 和 slot) -3:输出可读形式的数据页页头数据,并且包括记录中每个字段的可读形式
ok,接下来我们看看数据
PAGE HEADER部分,即该页面的前96个字节:
-m_pageId = (1:12980) 当前页面号码
-m_headerVersion = 1 版本号,始终为1
-m_type = 10 当前页面类型,m_type=1表示数据页面 10:IAM页
-m_typeFlagBits = 0x0 数据页和索引页为4,其他页为0
-m_level = 0 该页在索引页(B树)中的级数,0表示为叶子节点
-m_flagBits = 0x200 页面标志
-m_objId (AllocUnitId.idObj) = 1599 对象id 表id
-m_indexId (AllocUnitId.idInd) = 256 索引ID,0 代表堆, 1 代表聚集索引, 2-250 代表非聚集索引 大于250就是text或image字段
-Metadata: AllocUnitId = 72057594142720000 储单元的ID,sys.allocation_units.allocation_unit_id
-Metadata: PartitionId = 72057594138853376 数据页所在的分区号,sys.partitions.partition_id
-Metadata: IndexId = 0 跟m_indexId一样 对象的索引号,sys.objects.object_id&sys.indexes.index_id
-Metadata: ObjectId = 2060586429 跟m_objId 一样 该页面所属的对象的id,sys.objects.object_id
-m_prevPage = (0:0) 该数据页的前一页面
-m_nextPage = (1:56048) 该数据页的后一页面
-pminlen = 90 定长数据所占的字节数为90个字节
-m_slotCnt = 2 页面中的数据的行数,每页2条记录
-m_freeCnt = 6 页面中剩余的空间,还剩6字节的空间
-m_freeData = 8182 页面空闲空间的位置在8182这个位置,一个页面8KB约等于8192字节。页面空闲空间的位置在8182说明这个页面已经放不下数据了
-m_reservedCnt = 0 活动事务释放的字节数
-m_lsn = (6:524:11) 日志记录号
-m_xactReserved = 0 最新加入到m_reservedCnt领域的字节数
-m_xdesId = (0:0) 添加到m_reservedCnt的最近的事务id
-m_ghostRecCnt = 0 幻影数据的行数
-m_tornBits = 1 页的校验位或者被由数据库页面保护形式决定页面保护位取代