物理頁(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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM