SQL Server 資料儲存的基本單位是 **8 KB 頁面**。理解頁面內部結構,有助於掌握索引運作、碎片成因、DBCC 指令輸出解讀與效能調優。本文以簡單範例表剖析頁面三大區塊:頁頭、資料區、位移陣列。
+------------------+ 0x00 (位移 0)
| 頁頭 (96 B) | 固定 96 位元組
+------------------+ 0x60 (位移 96)
| 資料區 | 變長,依資料列大小向上增長
| (資料列堆疊) |
| |
+------------------+ 動態位移 (向下增長)
| 位移陣列 | 每列 2 位元組,記錄資料列起始位移
| (Slot Array) | 由頁尾向前增長
+------------------+ 0x1FFF (位移 8191)
| 欄位 | 位移 | 大小 | 說明 |
|---|---|---|---|
| page_id | 0 | 6 B | 檔案號:頁號 (FileID:PageID),如 1:100 |
| header_version | 6 | 1 B | 版本號 |
| type | 7 | 1 B | 頁面類型:1=資料頁, 2=索引頁, 10=IAM, 11=PFS... |
| free_cnt | 8 | 2 B | 頁面剩餘可用位元組數 |
| min_len | 10 | 2 B | 資料列最小長度 (用於快速判斷能否插入) |
| slot_cnt | 12 | 2 B | 目前資料列數 (Slot 數) |
| reserved_cnt | 14 | 2 B | 保留空間 (給前向指標/版本資訊) |
| lsn | 16 | 10 B | 最後修改此頁的 Log Sequence Number |
| ... 其他管理欄位 | ... | ... | 前向指標、Ghost 記錄計數、檢查碼等 |
關鍵:free_cnt 指向資料區結尾,**新資料列永遠寫入 free_cnt 位置**,寫入後更新 free_cnt 與 slot_cnt。
+----------------+----------------+----------------+----------+----------+
| 狀態位元組 | 固定長度資料 | 變長欄位計數 | 變長位移陣列 | 變長實際資料 |
| (2 B) | (依定義順序) | (2 B) | (每欄 2 B) | |
+----------------+----------------+----------------+----------+----------+
CREATE TABLE 定義順序緊密排列 (int, datetime, char...)。
頁頭:
page_id = 1:100, type = 1, free_cnt = 126, slot_cnt = 2
資料區 (從位移 96 開始):
Slot 0 (位移 96): 狀態位元組 | a=1 (4B) | b=100 (4B) -> 長度 10+4+4=18? 實際含 NULL 位圖等
Slot 1 (位移 114): 狀態位元組 | a=2 (4B) | b=200 (4B)
位移陣列 (從頁尾向前):
Slot 0 -> 96
Slot 1 -> 114
free_cnt 更新為 132 (下一筆寫入位置)
ghost_cleanup 背景執行緒標記 Ghost 記錄 → 空間可重用但位移陣列不重排。
DBCC TRACEON(3604); -- 輸出到用戶端
DBCC PAGE (DatabaseName, 1, 100, 3); -- DB, FileID, PageID, PrintOpt(0-3)
-- PrintOpt: 0=頁頭, 1=頁頭+位移陣列, 2=完整資料列, 3=完整+十六進位
FILLFACTOR = 80 預留 20% 空間,減少分裂 (代價:掃描更多頁面)。ALTER INDEX ... REBUILD/REORGANIZE 整理碎片、壓實頁面。