SQL Server頁有很多類型:
1 – 資料頁. 記錄堆或者聚集索引葉子級的資料
2 – 索引頁. 用于儲存聚集索引中的中間頁和根頁,或者非聚集索引的所有頁
3 – text mix page. A text page that holds small chunks of LOB values plus internal parts of text tree. These can be shared between LOB values in the same partition of an index or heap.
4 – text tree page. A text page that holds large chunks of LOB values from a single column value.
7 – sort page. A page that stores intermediate results during a sort operation.
8 – GAM page. Holds global allocation information about extents in a GAM interval (every data file is split into 4GB chunks – the number of extents that can be represented in a bitmap on a single database page). Basically whether an extent is allocated or not. GAM = Global Allocation Map. The first one is page 2 in each file. More on these in a later post.
9 – SGAM page. Holds global allocation information about extents in a GAM interval. Basically whether an extent is available for allocating mixed-pages. SGAM = Shared GAM. the first one is page 3 in each file. More on these in a later post.
10 – IAM page. Holds allocation information about which extents within a GAM interval are allocated to an index or allocation unit, in SQL Server 2000 and 2005 respectively. IAM = Index Allocation Map. More on these in a later post.
11 – PFS page. Holds allocation and free space information about pages within a PFS interval (every data file is also split into approx 64MB chunks – the number of pages that can be represented in a byte-map on a single database page. PFS = Page FreeSpace. The first one is page 1 in each file. More on these in a later post.
13 – boot page. Holds information about the database. There's only one of these in the database. It's page 9 in file 1.
15 – file header page. Holds information about the file. There's one per file and it's page 0 in the file.
16 – diff map page. Holds information about which extents in a GAM interval have changed since the last full or differential backup. The first one is page 6 in each file.
17 – ML map page. Holds information about which extents in a GAM interval have changed while in bulk-logged mode since the last backup. This is what allows you to switch to bulk-logged mode for bulk-loads and index rebuilds without worrying about breaking a backup chain. The first one is page 7 in each file.
PFS頁= 96+4+8088+4 間隔8088, 96頁頭,4行頭,slot0 8088 ,4slotlist
GAM/SGAM=96+4+90+4+7988+10 間隔 7988*8,96頁頭,4行頭,90slot0,4行頭,7988slot1,10slotlist
IAM頁 = 96+4+90+4+7988+10 96頁頭,4行頭,90slot0,4行頭,7988slot1,10slotlist
資料頁的基本格式:
資訊
助記符
大小(Byte)
狀态A
TagA
1
狀态B
TagB
固定長度大小
Fsize
2
固定長度資料
Fdata
Fsize-4
列數量
Ncol
NULL位圖(表中每列一個位;1表示對應列為null)
Nullbits
Ceil(Ncol/8)
行中存儲的可變長度列數
VarCount
可變長度的偏移陣列
VarOffset
2*VarCount
可變長資料
VarData
VarOffset[VarCount]-(Fsize+8-4+ Ceil(Ncol/8)+2*VarCount)
執行個體:
USE db_TestEnv
create table Index_test(id int,a varchar(10))
go
insert into Index_test select 100,'aaaaa'
go 4000
DBCC IND(db_TestEnv,Index_test,1)
DBCC PAGE(db_TestEnv,1,45969,1)
Slot 0, Offset 0x60,
Length 20, DumpStyle BYTE
Record Type =
PRIMARY_RECORD
Record Attributes =
NULL_BITMAP VARIABLE_COLUMNS
Record Size = 20
Memory Dump @0x613BC060
00000000: 30000800 64000000 02000001
00140061 †0...d..........a
00000010: 61616161
††††††††††††††††††††††††††††aaaa
a. 第一個位元組 TagA = 0x30 是由2個部分組成0x10(第4個位) 和0x20(第5個位),其中0x10表示有null列,0x20表示有可變長,0x40(第6個位)表示有版本标記,0x80(第7個位)表示TagB是否有值。
其中1-3位為行類型分别意思如下:
0:primary
record,堆上的資料頁或者聚集索引的葉子頁。
1:forwarded
record, 被轉發頁
2:forwarding
record,轉發根存頁(在行移動時會出現轉發頁和轉發根存頁如行溢出,可以檢視《深入解析sql server 2008》 5.7.4.1 和6.7.4.1的相關内容)
3:index record,聚集索引非葉子頁或者非聚集索引記錄
4:blob record,blob記錄
5:ghost index
record ,影子索引,被删除了沒被清理,可以使用顯示事務來觀察
6:ghost data
record,影子記錄,被删除了沒被清理,可以使用顯示事務來觀察
7:ghost
version record,幻想記錄,詳細請看《深入解析 SQL Server 2008》 10.7.3.8
b. 第二個位元組TagB有2個取值0x00,0x01.如果是0x01說明是被轉發頁的幻影頁。若為0x01則為TagA位元組的解釋
其他的不需要解釋了,更具上面的表格就可以。
索引頁行存儲格式分為2種:1.非葉子,2.葉子。但是會因為是堆表上的非聚集索引,還是聚集索引表上的非聚集索引有所不同。是否include對索引的存儲格式沒啥影響。
create table Index_test(id INT IDENTITY,a char(10),b VARCHAR(10))
insert into Index_test select 'aaaaa','bbb'
create nonclustered index ix_id_a on Index_test(id,a)
1.1 葉子頁
基本格式
行頭
Header
定長建值
Fkey
定長大小
表記錄Rowid(fileid:page:slote)
RowID
8(4資料頁,2頁号,2槽号)
索引記錄包含的字段個數
col
Ceil(可為空列數/8)
VarOffset[VarCount]-(Fkey+12+ Ceil(可為空列/8)+2*VarCount)
DBCC PAGE(db_TestEnv,1,41006,1)
Slot 0, Offset 0x60, Length 26, DumpStyle BYTE
Record Type = INDEX_RECORD
NULL_BITMAP
Record Size = 26
Memory Dump @0x6128C060
00000000:
16220100 00616161 61612020 202020f2 †."...aaaaa .
00000010:
e1000001 00200003 0000†††††††††††††††..... ....
a. 第一個位元組header有以下的意義:
0x40:對于記錄類型為索引記錄總為0
0x20: 包含可變長字段
0x10: 包含null位圖資料
1-3bit 表示是否是索引記錄
其他就不需要解釋了,按照表格可以輕易的得出。
1.2 非葉子頁
下一個頁所在的葉子節點(fileid:page)
KeyRowid
6(4資料頁,2頁号)
VarOffset[VarCount]-(Fkey+18+ Ceil(可為空列/8)+2*VarCount)
DBCC PAGE(db_TestEnv,1,41007,1)
Slot 0, Offset 0x60, Length 32, DumpStyle BYTE
Record Size = 32
Memory Dump @0x6095C060
16010000 00616161 61612020 202020f0 †.....aaaaa .
e1000001 0000007c 8d010001 00030000 †.......|........
葉子非葉子沒有什麼大的差別就是非葉子少了鍵值所在的葉子節點。需要注意的是唯一索引的非葉子比較特别沒有表記錄Rowid。
2.1葉子節點
定長建值+聚集索引定長值
可變長資料+聚集索引變長值
create table Index_test(id INT IDENTITY,a varchar(10),b VARCHAR(10),iid)
insert into Index_test select 'aaaaa','bb'
UPDATE dbo.Index_test SET iid = id+1
create clustered index cix_id_a on Index_test(id,a)
GO
CREATE NONCLUSTERED INDEX [idx__iid] ON [dbo].[Index_test]([iid],[b])
DBCC PAGE(db_TestEnv,1,164560,1)
Slot 0, Offset 0x60, Length 25, DumpStyle BYTE
Record Size = 25
Memory Dump @0x6083C060
36214104 00204104 00050000 02001400 †6!A.. A.........
19006262 61616161 61†††††††††††††††††..bbaaaaa
這個沒什麼難度,第一個位元組 Header 和其他的都一樣就是聚集索引上的非聚集索引會帶上聚集索引的key,在執行個體中:21410400 為自己的iid,20410400為id主鍵,6262為key的鍵,6161616161為聚集索引key。
如果聚集索引是可重複的,sql server會産生一個消除重複的數字,被當成可變長存放在可變成區域
2.2非葉子節點
UPDATE dbo.Index_test SET b = b+RTRIM(id) 重建索引
DBCC PAGE(db_TestEnv,1,177184,1)
Record Size = 32
Memory Dump @0x607AC060
36020000 00010000 00e0b302 00010005 †6...............
00000010: 00000200 1b002000 62623161
61616161 †...... .bb1aaaaa
第一個位元組和其他的都一樣不解釋,其他的按表格都可以解析
在聚集索引下隻有非葉子頁才是索引頁
一下層最小固定聚集索引建值
固定聚集索引建大小
一下層頁号(fileid:page)
create table Index_test(id INT IDENTITY,a varchar(10),b VARCHAR(10))
DBCC PAGE(db_TestEnv,1,51106,1)
Slot 0, Offset 0x60, Length 23, DumpStyle BYTE
Record Size = 23
Memory Dump @0x6056C060
36010000 0097b300 00010002 00000100 †6...............
00000010: 17006161
616161††††††††††††††††††††††..aaaaa
A. 第一個位元組header和其他的一樣
其他的表格中說明很詳細。
[1] SQL SERVER 2008資料庫技術内幕 李愛海
[3] 深入解析SQL SERVER 2008