SQL Server Page資料庫結構深入分析

laozhang發表於2019-02-10

  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是用於儲存資料的,叫做Data Page,有些Page是用於儲存索引結構中的中間節點的,叫做Index Page,有些Page是SQL Server儲存引擎使用的,用於管理Page的,叫做系統頁。本文關注的是Data Page和Index Page,跟資料表有關。

  日誌檔案沒有Page結構,它是由一系列的日誌記錄構成的。

一,Page的結構

  每一個Page都由 頭部(Header),內容(Content)和行偏移量(Offset)組成,頭部是在Page的開始處,佔用96Bytes,用於儲存Page的編號,Page的型別,分配單元(Allocation Unit)等系統資訊。注:在單個Page中最多儲存8060Bytes的資料。

  The maximum amount of data and overhead that is contained in a single row on a page is 8,060 bytes (8 KB).

  資料行儲存在Page Header之後,資料行在Page中的物理儲存是無序的,行的邏輯順序是由行偏移(Row Offset)確定的,行偏移儲存在Page的末尾,每一個行偏移是一個Slot,佔用2B。行偏移連續排列在Page的末尾,稱作槽陣列(Slot Array)。行偏移以倒序方式儲存行的偏移量,這意味著,從Page末尾向Page 開頭計數,第一行的偏移量儲存在Page的末尾Slot中,第二行的偏移量儲存在Page末尾的第二個Slot中。

二,檢視Page頭部資訊

  Page頭部資訊儲存的是Page的系統資訊,可以使用非正式的命令來檢視:?

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

  引數:file_id是資料庫檔案的ID;page_number是Page在當前檔案中的編號;print_option是指列印資訊的詳細程度,預設值是0,只列印Page Header。

  例如,檢視資源識別符號:15:1:8777733 Page的頭部資訊:?

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

  在我的資料庫中,該Page的頭部資訊(移除Buffer的資料)如下所示,?

  1. PAGE: (1:8777733)
  2.  
  3. PAGE HEADER:
  4. Page @0x0000005188B02000
  5.  
  6. m_pageId = (1:8777733) m_headerVersion = 1 m_type = 1
  7. m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x220
  8. m_objId (AllocUnitId.idObj) = 28503 m_indexId (AllocUnitId.idInd) = 256
  9. Metadata: AllocUnitId = 72057595905900544
  10. Metadata: PartitionId = 72057594059423744 Metadata: IndexId = 1
  11. Metadata: ObjectId = 1029578706 m_prevPage = (1:8777732) m_nextPage = (1:8777734)
  12. pminlen = 16 m_slotCnt = 2 m_freeCnt = 4513
  13. m_freeData = 3675 m_reservedCnt = 0 m_lsn = (1212327:16:558)
  14. m_xactReserved = 0 m_xdesId = (0:799026688) m_ghostRecCnt = 0
  15. m_tornBits = -1518328013 DB Frag ID = 1
  16.  
  17. Allocation Status
  18. GAM (1:8690944) = ALLOCATED SGAM (1:8690945) = NOT ALLOCATED
  19. PFS (1:8775480) = 0x40 ALLOCATED 0_PCT_FULL DIFF (1:8690950) = CHANGED
  20. 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;

  原文連結:http://www.cnblogs.com/ljhdo/p/4803095.html

相關文章