SQL Server 2000 單列最大 8060 位元組 (可用 8039)。SQL Server 2005 引入行溢出儲存,允許變長欄位總和超過 8060 位元組,透過 24 位元組指標引用 ROW_OVERFLOW 頁面。
核心機制
- 固定長度欄位總和仍不可超過 8060 位元組。
- 變長欄位 (
VARCHAR/VARBINARY/NVARCHAR/MAX) 可推至行溢出頁面。
- 每個變長欄位在資料列中固定佔用 2 位元組 (位移陣列),無論是否溢出。
- 溢出時,原資料列保留 24 位元組指標,指向 ROW_OVERFLOW 頁面的實際資料。
指標結構 (24 位元組)
| 位移 | 大小 | 內容 |
| 0 | 2 | 溢出欄位類型代碼 |
| 2 | 1 | B-tree 層級 |
| 3 | 1 | 保留 |
| 4 | 4 | LOB 更新版本號 (供 DBCC CHECKTABLE) |
| 8 | 4 | 隨機驗證碼 (LOB 生命期不變) |
| 12 | 4 | 資料長度 (如 0x00000BB8 = 3000) |
| 16 | 4 | 頁面號 (Page ID) |
| 20 | 2 | 檔案號 (File ID) |
| 22 | 2 | Slot 號 |
實驗驗證
CREATE TABLE dbo.RowOverflowTest (
Col1 CHAR(7000), -- 固定 7000
Col2 VARCHAR(3000), -- 變長
Col3 VARCHAR(3000) -- 變長
);
INSERT INTO dbo.RowOverflowTest VALUES ('aaa', REPLICATE('b',1000), REPLICATE('c',1000));
-- 單列總長 ~7000 + 2*2 + 24*2 = 7052 位元組 (固定部份) + 溢出資料
-- 查詢頁面分佈
DBCC IND('TestDB', 'RowOverflowTest', -1);
-- 假設頁面: 89 (IAM), 80 (Data), 6321 (IAM), 6315 (RowOverflow Data)
DBCC TRACEON(3604);
DBCC PAGE('TestDB', 1, 80, 1); -- 主資料頁
DBCC PAGE('TestDB', 1, 6315, 1); -- 行溢出頁 (類型=LOB)
主資料頁關鍵輸出解讀
-- 位移 0x1B50 處
03 00 F8 02 -- 3欄位, NULL位圖0xF8, 2變長欄位
00 7D 9B 9B -- 變長欄位結束位移陣列 (Col2結束, Col3結束)
...
02 00 00 65 01 00 00 00 F6 5C 00 00 B8 0B 00 00 AB 18 00 00 01 00 00 00 -- Col2 指標 (24B)
02 00 00 65 01 00 00 00 C0 47 00 00 B8 0B 00 00 AB 18 00 00 01 00 01 00 -- Col3 指標 (24B)
行溢出頁面 (LOB 頁面) 特徵
- 頁面類型
m_type = 3 (Text Mixed) 或 4 (Text Tree)。
- 儲存實際變長資料內容,以 B-tree 組織大型值。
- 可透過
DBCC PAGE 檢視資料完整性。
效能與設計建議
| 場景 | 影響 | 建議 |
| 大量變長欄位頻繁更新 | 產生大量行溢出、碎片、記錄檔 | 拆分至獨立表、使用 FILESTREAM/FileTable |
| 查詢常讀取溢出欄位 | 額外 I/O 跳轉 ROW_OVERFLOW 頁面 | 避免 SELECT *,僅查詢所需欄位 |
| 索引包含溢出欄位 | 不可包含 LOB/MAX 欄位於索引鍵 | 僅 INCLUDE 非 MAX 變長欄位 |
| 資料壓縮 | ROW/頁面壓縮不壓縮 ROW_OVERFLOW 資料 | 評估壓縮效益需排除溢出部分 |
查詢行溢出統計
SELECT
OBJECT_NAME(p.object_id) AS TableName,
i.name AS IndexName,
p.partition_number,
SUM(CASE WHEN au.type_desc = 'ROW_OVERFLOW_DATA' THEN p.rows ELSE 0 END) AS OverflowRows,
SUM(CASE WHEN au.type_desc = 'ROW_OVERFLOW_DATA' THEN au.total_pages ELSE 0 END) AS OverflowPages
FROM sys.partitions p
JOIN sys.allocation_units au ON p.partition_id = au.container_id
JOIN sys.indexes i ON p.object_id = i.object_id AND p.index_id = i.index_id
WHERE au.type_desc = 'ROW_OVERFLOW_DATA'
GROUP BY p.object_id, i.name, p.partition_number;
理解行溢出機制,有助於容量規劃、效能調校、避免隱性 I/O 罰則,是 SQL Server 進階 DBA 必修課題。
- 上一篇文章: SQL Server 2005 OUTPUT 子句實戰:INSERT/UPDATE/DELETE 返回受影響資料
- 下一篇文章: SQL Server Agent 錯誤日誌完整管理指南:配置、查看、循環與常見問題
Copyright ©
程式碼之家 All Rights Reserved