1. 程式人生 > >SQL Server 儲存(3/8):理解GAM和SGAM頁

SQL Server 儲存(3/8):理解GAM和SGAM頁

我們知道SQL Server在8K 的頁裡儲存資料。分割槽就是物理上連續的8個頁。當我們建立一個數據庫,資料檔案會被邏輯分為頁和區,當用戶物件建立時,頁會分配給它用來儲存資料。GAM(Global Allocation Map)和SGAM(Shared Global Allocation Map)頁用來跟蹤SQL Server裡空間分配情況。這裡我們會一起討論下SQL Server的空間分配,還有GAM和SGAM怎麼幫助我們分配空間。

在SQL Server裡有2類區:

統一區(Uniform Extent) :區屬於一個使用者物件。這些區的所有8頁歸一個物件所有。

混合區(Mixed Extent)

:區屬於各個使用者物件。即區裡的每個頁都可以屬於不同使用者物件。

為了更好的管理空間分配,如果一個表或索引大小小於8頁(即64k),SQL Server會分配混合區的頁,而不是統一區的頁。

我們在SQL Server裡驗證下。

新建一個表(這個表剛好一條記錄一個頁面),並插入26條記錄,並通過DBCC IND檢視這個表的相關頁面:

 1 USE InternalStorageFormat
 2 GO
 3 
 4 IF EXISTS ( SELECT  *
 5             FROM    sysobjects
 6             WHERE   id =
OBJECT_ID(N'[dbo].[TestSpaceAllocation]') 7 AND OBJECTPROPERTY(id, N'IsUserTable') = 1 ) 8 DROP TABLE dbo.TestSpaceAllocation 9 10 CREATE TABLE TestSpaceAllocation( 11 Name CHAR(8000) 12 ) 13 GO 14 15 INSERT INTO TestSpaceAllocation VALUES('Woody') 16 GO 26 17
18 DBCC IND('InternalStorageFormat','TestSpaceAllocation',1)

從上圖我們可以清楚的看到,綠色區域的第一個8頁不屬於同個區(混合區),因為頁面號不連續,207與94752之間有缺口。接下來藍色紅色區域是屬於同個區(統一區),因為它們的頁面號是連續的。當我們以碎片級別來看待這個情況時,可以發現表越小,碎片越高。即使你用索引重建,這個高碎片也不會減少。這個背後的原因就是SQL Server分配新的表或索引物件時,總是首先從混合區分配空間。
SQL Server為新表或索引從混合區開始分配頁。一旦表增長超過8頁。SQL Server需要從統一區分配頁。當表或索引為新的或修改的資料需要更多的容納空間時,SQL Server需要這些表或索引分配頁。如果表或索引的大小小於8頁。SQL Sever需要從混合區給它們分配空間。如果大小超過8頁,SQL Server需要從統一區分配頁。SQL使用2類不同的頁來更好管理這個分配操作。

全域性分配對映表(GAM: Global Allocation Map Pages) :GAM頁記錄哪些些區已被使用分配。對於每個區,GAM都有一個位。如果這個位是1,表示對應的區是空閒可用的。如果這個位是0,表示對應區被統一區或混合區使用。一個GAM頁可以儲存64000個區的使用資訊。這就是說,一個GAM可以儲存近4G(64000 * 8 * 8/ 1024)資料檔案的使用資訊。簡單來說,一個7G的資料檔案會有2個GAM頁。
共享全域性分配對映表(SGAM: Shared Global Allocation Map Pages) :SGAM頁記錄哪些區已被作為混合區使用並至少有一個可用的空閒頁。對於每個區,SGAM都有一個位。如果這個位是1,表示對應的區作為混合區使用並至少有一個可用的空閒頁。如果這個位是0,表示這個區既沒被混合區使用(作為統一區),或這個區的所有頁都作為混合區使用了。一個SGAM頁可以儲存64000個區的使用資訊。這就是說,一個SGAM可以儲存近4G(64000 * 8 * 8/ 1024)資料檔案的使用資訊。簡單來說,一個7G的資料檔案會有2個SGAM頁。

GAM和SGAM頁幫助資料庫引擎進行區管理。分配一個區,資料庫引擎查詢標記1的GAM頁,然後標記為0。如果那個區是作為混合區分配,它會在SGAM頁把對應區的標記為1。如果那個區是作為統一區分配,那就沒有必要在SGAM裡修改對應位標記。找一個有空頁的混合區,資料庫引擎在SGAM頁查詢標記為1的位。如果沒找到,資料檔案已經滿了。解除一個區分配,資料庫引擎會把對應GAM頁裡對應位設定為1,SGAM頁裡對應標記設定為0。

在每個資料檔案裡,第3個頁(頁號2,頁號從0開始)是GAM頁,第4個頁(頁號3,頁號從0開始)是SGAM頁。第1個頁(頁號0)是檔案頭(file header),第2個頁(頁號1)是PFS(Page Free Space)頁。我們可以使用DBCC PAGE命令檢視GAM和SGAM頁。

我們在AdventureWorks2008R2資料庫裡驗證下:

1 USE AdventureWorks2008R2
2 
3 DBCC TRACEON(3604)
4 GO
5 DBCC page('AdventureWorks2008R2',1,2,3)

輸出的結果最後一個部分:

第1行表示,在頁0到頁23112之間的區都已經被分配,也就是說頁號從0到23129的頁都被分配。

第2行表示,在頁23120到頁25072之間的區都沒被分配,也就是說頁號從22120到頁25079的頁都未被分配。

我們一起來看看分配的頁23112和未分配的頁23120在頁頭分配資訊裡的GAM分配情況。

1 DBCC TRACEON(3604)
2 GO
3 DBCC page('AdventureWorks2008R2',1,23112,1)

1 DBCC TRACEON(3604)
2 GO
3 DBCC page('AdventureWorks2008R2',1,23120,1)

可以看到在GAM頁的分配資訊和在對應頁裡頁頭的分配資訊(Allocation Statu)是一致的。

我們來看看SGAM頁的分配情況:

1 DBCC TRACEON(3604)
2 GO
3 DBCC page('AdventureWorks2008R2',1,3,3)

第1行表示,在頁0到頁11752之間的區都已經未被分配,也就是說這些區沒被分配,或者是統一區,或者是沒有空頁的混合區,這裡應該是統一區。

第2行表示,自頁11760的區開始是混合區,並且至少有1個可用的頁。

參考文章: