IF OBJECT_ID('Test') IS NOT NULL DROP TABLE Test;
GO
CREATE TABLE Test (Id INT, Birth DATETIME, Name CHAR(10));
INSERT INTO Test SELECT 1, '2009-11-27', 'aaaa' UNION ALL SELECT 2, '2009-11-27', 'aaaa';
EXEC sp_spaceused 'Test';
-- 結果:2 列,保留 16KB,資料 8KB,索引 8KB
DBCC IND('TestDB', 'Test', 0); -- 列出所有頁,找 PageType=1 (資料頁),假設 PageId=89
DBCC TRACEON(3604); -- 輸出導向用戶端
DBCC PAGE('TestDB', 1, 89, 1); -- 資料庫ID=1, 檔案ID=1, 頁碼=89, 輸出選項=1 (頁頭+資料)
| 欄位 | 範例值 | 含義 |
|---|---|---|
m_pageId | (1:89) | 頁面編號 (檔案號:頁號) |
m_headerVersion | 1 | 頭部版本,SQL 7.0 後固定為 1 |
m_type | 1 | 頁面類型:1=資料頁、2=索引頁、10=IAM 頁... |
m_typeFlagBits | 0x4 | 資料/索引頁為 0x4,其他為 0 |
m_level | 0 | B 樹層級,0=葉層 |
m_flagBits | 0x8000 | 頁面旗標 (如鬼魂記錄、備份標記等) |
m_objId / m_indexId | 83 / 256 | 舊版儲存單元 ID 組成 |
Metadata: AllocUnitId | 72057594043367424 | 儲存單元 ID (新版統一識別) |
Metadata: PartitionId | 72057594038386688 | 分區 ID |
Metadata: IndexId | 0 | 索引 ID (0=堆積表) |
Metadata: ObjectId | 2089058478 | 物件 ID (`OBJECT_ID('Test')`) |
m_prevPage / m_nextPage | (0:0) | 雙向鏈表指標,資料頁串聯順序 |
pminlen | 26 | 固定長度資料最小長度 (含 4 字節列開銷) |
m_slotCnt | 2 | 頁面列數 (槽位數) |
m_freeCnt | 8034 | 頁面剩餘可用空間 (位元組) |
m_freeData | 154 | 從頁首到最後一列資料結尾的位移 |
m_reservedCnt | 0 | 作用中交易保留的空間 |
m_lsn | (30:170:20) | 最後修改日誌序號 (LSN) |
m_xactReserved | 0 | 最新加入保留空間的交易位元組數 |
m_xdesId | (0:0) | 最近加入保留空間的交易描述符 ID |
m_ghostRecCnt | 0 | 鬼魂記錄數 (已刪除待清理) |
m_tornBits | 0 | 頁面校驗和 / torn page 偵測位元 |
4 字節列開銷 (狀態位元、長度、NULL 位圖指標) + 4 字節 INT (Id) + 8 字節 DATETIME (Birth) + 10 字節 CHAR(10) (Name) = 26 字節 ✓
96 字節頁面頭部固定大小 + (7 字節槽位陣列開銷/列? 實為 2 字節/列槽位陣列 + 列資料開銷) * 2 列 實際計算:96 (頭部) + 2*2 (槽位陣列) + 2*26 (列資料) = 96 + 4 + 52 = 152 DBCC 輸出 154,差 2 字節可能含版本資訊/保留欄位,大體吻合。
8192 (8KB 頁面總大小) - 154 (m_freeData) - 4 (2 列槽位陣列 2*2) = 8034 ✓
頁面實際儲存 2 列資料 ✓
資料頁頭部是 SQL Server 儲存引擎的「元資料中樞」。透過 `DBCC PAGE` 解析 `pminlen`、`m_freeData`、`m_freeCnt`、`m_slotCnt` 等核心欄位,可精確重構頁面佈局、驗證空間計算、診斷碎片與結構變更影響。掌握頁面結構,是進階效能調校、災難恢復、核心引擎研究的必修課。