
SQL Server數據頁的結構大體包括三個部分,即標頭、數據行和行偏移量。
現在讓我們正式進入數據頁面去看一下數據頁面的構造,讓我們首先去訪問一下該表的數據首頁即第224個頁面。
Dbcc page(testdb,1,224,2)
PAGE HEADER部分,即該頁面的前96個字節。
m_pageId = (1:224) | 當前頁面號碼 |
m_headerVersion = 1 | 版本號,始終為1 |
m_type = 1 | 當前頁面類型,m_type=1表示數據頁面 |
m_typeFlagBits = 0x4 | 數據頁和索引頁為4,其他頁為0 |
m_level = 0 | 該頁在索引頁(B樹)中的級數,0表示為葉子節點 |
m_flagBits = 0x8200 | 頁面標志 |
m_objId (AllocUnitId.idObj) = 94 | |
m_indexId (AllocUnitId.idInd) = 256 | |
Metadata: AllocUnitId = 72057594044088320 | 存儲單元的ID,sys.allocation_units.allocation_unit_id |
Metadata: PartitionId = 72057594039107584 | 數據頁所在的分區號,sys.partitions.partition_id |
Metadata: IndexId = 0 | 對象的索引號,sys.objects.object_id&sys.indexes.index_id |
Metadata: ObjectId = 133575514 | 該頁面所屬的對象的id,sys.objects.object_id |
m_prevPage = (0:0) | 該數據頁的前一頁面 |
m_nextPage = (0:0) | 該數據頁的后一頁面 |
pminlen = 108 | 定長數據所占的字節數為108個字節 ID INT IDENTITY(1,1) NOT NULL, type CHAR(100) NOT NULL, 共計104個字節,每個定長字段需要2個字節的管理字節 |
m_slotCnt = 62 | 頁面中的數據的行數,每頁62條記錄 |
m_freeCnt = 293 | 頁面中剩余的空間,還剩293字節的空間 |
m_freeData = 7775 | 從第一個字節到最后一個字節的空間字節數(包括96字節的文件頭的長度) |
m_reservedCnt = 0 | 活動事務釋放的字節數 |
m_lsn = (67:272:3) | 日志記錄號 |
m_xactReserved = 0 | 最新加入到m_reservedCnt領域的字節數 |
m_xdesId = (0:0) | 添加到m_reservedCnt的最近的事務id |
m_ghostRecCnt = 0 | 幻影數據的行數 |
m_tornBits = 1213019927 | 頁的校驗位或者被由數據庫頁面保護形式決定分頁保護位取代 |
上在頁的尾部還有個行偏移矩陣,記錄了每條記錄的起始位置,每條記錄需要2個字節來記錄該位置,所以62條記錄共計124個維護字節,加上293個剩余空間和實際已使用的7775個字節,剛好8192個字節,即一頁。
從Offset table和page結構可以知道,第一條記錄從第96個字節開始。
ID | name | Type | other | describle |
1 | name1 | 1111111111111111111111111111111111. | 8 | NULL |
如前文所說,關于數據的存儲從第96個字節開始
關于數據行的結構我們還可以采用稍微宏觀一些的視角來查看。
其中狀態A為如下說明:
bit0:版本信息,在SQL Server 2005/08總是為0
bit1-3: 0=(primary record);1=(forwarded record);2=(forwarding stud);3=(index record);4=(溢出數據);5=(ghost索引記錄);6=(ghost數據記錄)
bit4:表示存在NULL位圖(在數據行里SQL2005/08總存在NULL位圖)
bit5:表示存在變長列
bit6:未啟用
bit7:表示存在幽靈記錄
本例中30->00110000 它是一個行屬性的位圖 從高位存到地位(右邊第一位是bit0),bit4為1即存在變長列的字段,因為在SQLServer2005/2008中總存在NULL位圖,所以bit5也為1。
狀態位B在SQLServer2005//2008中未啟用,所以為00
記錄定長部分的長度為2個字節,是所有定長字段的長度之和加4,該處為int類型4個字節,char(100)為100個字節,再加上4,所以為108,換算成16進制即6c。
緊跟其后的為定長字段的內容,即ID字段的4個字節和TYPE字段的100個字節。
固定長度的字段數據之后,是該表的總字段數,用兩個字節表示,本表包括5個字段所以為05 00。
NULL位圖:f0->11110000 因為該表只有列 所以只需要看后面個,1表示該行的對應列為NULL或者該位圖未使用。本表前4個字段不為空,第5個為空,第6-8未使用。
接下來是行內存儲數據的變長列的數目:0200->00000000 00000010=2 表示該行存儲了列name和other字段的數據。
第一變長列數據終止位置為:7a00->00000000 01111010=122=1+1+2+(4+100)+2+ceiling(5/8)+2+2+2+len(“name1”)
第二變長列數據終止位置:7b00->00000000 01111011=123 實際上就是在前者的基礎上加了第二個變長列的字段長度。
1+1+2+(4+100)+2+ceiling(5/8)+2+2+2+len(“name1”)+len(“8”)
第一列變長列的數據: 6e616d 6531換算成字符即'name1'
第二列變長列的數據:38換算成字符即8