簡介
我們已經知道SQL Server IO最小的單位是頁,連續的8個頁是一個區。SQL Server需要一種方式來知道其所管轄的數據庫中的空間使用情況,這就是GAM頁和SGAM頁。
Global Allocation Map Page
GAM(全局分配位圖)是用於標識SQL Server空間使用的位圖的頁。位於數據庫的第3個頁,也就是頁號是2的頁。下面我們通過新建一個數據庫來看其GAM的結構。創建測試數據庫的代碼如代碼所示。
CREATE DATABASE [test] ON PRIMARY ( NAME = N'test', FILENAME = N'C:\Test\test.mdf' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ) LOG ON ( NAME = N'test_log', FILENAME = N'C:\Test\test_log.ldf' , SIZE = 2048KB , MAXSIZE = 2048GB , FILEGROWTH = 10%) GO
代碼1.創建測試數據庫
數據庫創建成功后,通過查看數據庫頁號為2的頁。我們看到如圖1所示的結果。
圖1.GAM頁示例
我們看到頁內的數據通過16進制表示。也就是一個數字是4比特,兩個是一字節。其中前4個字節0000381f是系統信息,slot1的后10個字節也是系統信息。其余的每位表示SQL Server的一個區的狀態,0表示已分配,1表示未分配。下面我們就通過圖1所示的GAM頁來計算一下這個數據庫所占的空間。
我們可以看到,由於數據庫剛剛創建,分配的空間在第4-8個字節就能表示,也就是0001c0ff。下面將0001c0ff由16進制化為2進制。結果是
0000 0000 0000 0001 1100 0000 1111 1111
通過計算,可以看出,上面的bit中有21個0,也就是目前數據庫已經分配了21個區,我們知道每個區是8*8k=64K。因此算出這個數據庫占用空間(21*64)/1024=1.3125MB≈1.31MB
下面我們通過SSMS來看數據庫實際占用的空間,如圖2所示。
圖2.通過SSMS來看數據庫所占的空間
通過上面的計算3-1.69=1.31MB和通過GAM頁進行計算的結果完全吻合。
那可能大家會有疑問了,那如果數據庫增長超過一個GAM所能表示的區的范圍那該怎么辦?答案很簡單,就是再創建一個GAM頁,第二個GAM頁的位置也可以通過圖1中的信息進行計算。圖1中slot1有7992個字節,其中前四個字節用於存儲系統信息,后面7988字節用於表示區的情況,因此所能表示的區是7988*8=63904,橫跨的頁的范圍是511232,所以第511232+1頁應該是下一個GAM頁,而頁號就會是511232頁。這個區間也就是所謂的GAM Interval,接近4GB。
Shared Global Allocation Map Page
通過GAM頁可知,分配空間的最小單位是區。但假如一個非常小的索引或是表只占1KB,但要分給其64K的空間就顯得過於奢侈了。所以當幾個表或索引都很小時,可以讓幾個表或索引公用一個區,這類區就是混合區。而只能讓一個表或索引使用的區就是統一區。SGAM位於數據庫的第四頁,也就是GAM的下一個頁。頁號為3。通過和GAM相同位置的bit組合,就能知道空間的狀態。所能表示的幾種狀態如表1所示。
GAM | SGAM位 | |
未分配 | 1 | 0 |
統一區或空間使用完的混合區 | 0 | 0 |
含有可分配空間的混合區 | 0 | 1 |
表1.SGAM和GAM
通過SGAM和GAM的組合,SQL Server就能知道該從哪里分配空間。
第二個SGAM頁位於第二個GAM頁之后,也就是頁號為511233的頁。依此類推。