Sql-Server

SQL Server 的 8 KB 數據頁中未使用 512 字節

  • August 16, 2016

我創建了下表:

CREATE TABLE dbo.TestStructure
(
   id INT NOT NULL,
   filler1 CHAR(36) NOT NULL,
   filler2 CHAR(216) NOT NULL
);

然後創建了一個聚集索引:

CREATE CLUSTERED INDEX idx_cl_id 
ON dbo.TestStructure(id);

接下來我用 30 行填充它,每個大小為 256 字節(基於表聲明):

DECLARE @i AS int = 0;

WHILE @i < 30
BEGIN
   SET @i = @i + 1;

   INSERT INTO dbo.TestStructure (id, filler1, filler2)
   VALUES (@i, 'a', 'b');
END;

現在根據我在“Training Kit (Exam 70-461): Querying Microsoft SQL Server 2012 (Itzik Ben-Gan)”一書中讀到的資訊:

SQL Server 在內部以頁的形式組織數據文件中的數據。一個頁面是一個 8 KB 的單元,屬於單個對象;例如,表或索引。一頁是讀寫的最小單位。頁面被進一步組織成範圍。一個盤區由八個連續的頁面組成。一個範圍內的頁面可以屬於單個對像或多個對象。如果頁面屬於多個對象,則該範圍稱為混合範圍;如果頁面屬於單個對象,則該範圍稱為統一範圍。SQL Server 將對象的前八頁儲存在混合範圍中。當一個對象超過八頁時,SQL Server 會為此對象分配額外的統一擴展區。有了這種組織方式,小物體浪費的空間更少,大物體的碎片更少。

所以在這裡我有第一個混合範圍 8KB 頁面,填充了 7680 字節(我插入了 30 次 256 字節大小的行,所以 30 * 256 = 7680),檢查我執行 size check proc 的大小 - 它返回以下結果

index_type_desc: CLUSTERED INDEX
index_depth: 1
index_level: 0 
page_count: 1 
record_count: 30 
avg_page_space_used_in_percent: 98.1961947121324
name : TestStructure        
rows : 30   
reserved :  16 KB
data : 8 KB 
index_size : 8 KB       
unused :    0 KB

因此為表保留了 16 KB,第一個 8 KB 頁用於 Root IAM 頁,第二個用於葉數據儲存頁,8KB 佔用約 7.5 KB,現在當我插入一個 256 字節的新行時:

INSERT INTO dbo.TestStructure (id, filler1, filler2)
VALUES (1, 'a', 'b');

雖然它有 256 字節的空間(7680 b + 256 = 7936,仍然小於 8KB),但它沒有儲存在同一頁中,創建了一個新數據頁,但新行可以放在同一個舊頁上, 為什麼 SQL Server 在可以節省空間和搜尋時間的情況下創建一個新頁面並將其插入現有頁面?

注意:堆索引中也發生了同樣的事情。

您的數據行不是 256 字節。每一個更像是 263 個字節。由於 SQL Server 中數據行的結構,純固定長度數據類型的數據行具有額外的成本。看看這個網站並了解數據行是如何組成的。 http://aboutsqlserver.com/2013/10/15/sql-server-storage-engine-data-pages-and-data-rows/

因此,在您的範例中,您有一個 256 字節的數據行,添加 2 個字節作為狀態位,2 個字節作為列數,2 個字節作為數據長度,另外 1 個左右作為空點陣圖。即 263 * 30 = 7,890 字節。添加另一個 263 並且您超過了 8kb 頁面限制,這將強制創建另一個頁面。

引用自:https://dba.stackexchange.com/questions/146750