SQL Server 2008儲存結構之IAM結構

bq_wang發表於2010-11-02
索引分配對映(Index Allocation Map,IAM)頁面在4 GB的區間中跟蹤被一個分配單元所使用的區。一個分配單元就是一組頁面,這些頁面屬於一個資料表或索引的單個分割槽。它由下面三種型別頁面中的一種組成:含 有常規的行內資料的頁面、含有大型物件(Large Object,LOB)資料的頁面和含有行溢位資料的頁面。 其實SQL Server的資料頁面型別與Oracle的段的概念有些類似,一個物件包含若干段,而一個段只能屬於一個物件。

  假如一張在四個分割槽上 的含有所有三種型別的資料(行內資料、LOB資料和行溢位資料)的表將會有至少12個IAM頁面。單張IAM頁面也是僅僅覆蓋單個檔案的4GB區間,所以 如果分割槽跨越多個檔案,那麼就會有多個IAM頁面,同時如果檔案大小超過4GB,並且分割槽使用了一個4 GB區間以外的資料頁,那麼也將會有額外的IAM資料頁。

  一個IAM資料頁包含一個頁頭(IAM頁頭),該頁頭包含有8個頁面指標槽, 還有一組位元位用來將一個範圍內的區對映到一個檔案,這個檔案並不必一定就是IAM頁面所在的那個檔案。頁頭包含有在IAM對映範圍內的第一個區的地址。 8個頁面指標槽可能包含指向某些屬於相關物件頁面的指標,這些物件被包含在混合型別的區中,對一個物件來說,只有第一個IAM頁面含有這些指標的值。一旦 一個物件佔用的頁面超過8個,它所有的區都會是統一型別的區——這意味著一個物件決不會需要超過8個指標來指向處於混合型別區中的頁面。如果一張表中的數 據行已被刪除,該表實際上可以使用的指標數不到8個。位元位對映中的每一個位元位代表了該範圍內的一個區,而不論該區是否被分配給了擁有該IAM的物件。 如果一個位元位是開啟的,那麼在此範圍內相關的區就是被分配給擁有 IAM的物件的;如果一個位元位是關閉的,那麼此範圍內相關的區沒有被分配給擁有該IAM的物件。

  IAM頁面在需要的時候被分配給每一個物件,並且位於資料庫中的隨機位置。每一個IAM頁面覆蓋的可能範圍大約是512 000個頁面。

  看概念總歸是比較枯燥的,我們可以構建一個具體的例子。

  在構建例子之前我們首先需要建立一個把地址轉換為具體頁碼的函式。

#div_code img { border: 0px none; }
CREATE FUNCTION [dbo].f_get_page(@page_num BINARY(6))
RETURNS VARCHAR(
11)
AS
BEGIN
RETURN(CONVERT(VARCHAR(
2),(CONVERT(INT,SUBSTRING(@page_num,6,1))*POWER(2,8))+
        (CONVERT(
INT,SUBSTRING(@page_num,5,1))))+':'+
        CONVERT(VARCHAR(11),
        (CONVERT(
INT,SUBSTRING(@page_num,4,1))*POWER(2,24))+
        (CONVERT(
INT,SUBSTRING(@page_num,3,1))*POWER(2,16))+
        (CONVERT(
INT,SUBSTRING(@page_num,2,1))*POWER(2,8))+
        (CONVERT(
INT,SUBSTRING(@page_num,1,1)))))
END
--根據master.sys.objects構建一張叫testIAM的資料表
SELECT * INTO testIAM FROM master.sys.objects    
--然後我們根據之前所知曉的資訊,獲取testIAM物件的IAM地址,並根據f_get_page函式將地址轉換為相應的頁面
SELECT total_pages,used_pages,data_pages,
       first_page,root_page,first_iam_page,
       testdb.dbo.f_get_page(first_page) first_page_address,
       testdb.dbo.f_get_page(root_page) root_address,
       testdb.dbo.f_get_page(first_iam_page) IAM_address
  FROM sys.system_internals_allocation_units
WHERE container_id IN (
SELECT partition_id FROM sys.partitions
                         WHERE object_id in (
SELECT object_id  FROM sys.objects
                                              WHERE name IN (
'testIAM')))

dbcc page(testdb,
1,80,3)

1
 

  從dbcc page(testdb,1,80,3)可以得到以下資訊

1
 

    因為master.sys.objects的物件只有49條資料,所以只分配了2個頁面,根據前文所述,分配8個頁面(包括8)以內的物件,SQL Server將以把該物件的資料分配到混合型別的分割槽上,如上SQL Server給予testIAM表只分配了第一個檔案的第77和第89個頁面,而並沒有分配同一型別的分割槽的頁面。  

  假如我們master.sys.objects的資料反覆插入testIAM表,讓我們觀察一下相應的頁面分配情況。

#div_code img { border: 0px none; }
declare @maxtime int
set @maxtime=0
while @maxtime<20
begin
insert into testiam
select * from sys.objects
set @maxtime=@maxtime+1
end
select * from testiam
--我們首先還是執行以下system_internals_allcation_units系統表
SELECT total_pages,used_pages,data_pages,
       first_page,root_page,first_iam_page,
       testdb.dbo.f_get_page(first_page) first_page_address,
       testdb.dbo.f_get_page(root_page) root_address,
       testdb.dbo.f_get_page(first_iam_page) IAM_address
  FROM sys.system_internals_allocation_units
WHERE container_id IN (
SELECT partition_id FROM sys.partitions
                         WHERE object_id in (
SELECT object_id  FROM sys.objects
                                              WHERE name IN (
'testIAM')))

--透過上面的結果,我們可以觀察到這次SQL Server共分配了17個頁面,其中使用了15個頁面,而資料頁面只有14個,這是為什麼呢?
--接著我們再次執行dbcc page命令
dbcc page(testdb,
1,80,3)

2
 

   結果如下

2
 

   從上述我們可知,slot 0到slot 7一共分配了8個混合型別區的頁面,由於已經超過8頁,所以SQL Server再次分配空間時,就會把同一型別的區分配給該物件,一個區包括8個頁面,所以SQL Server為testIAM表共分配了16個頁面,資料頁面14個,已使用的頁面除了資料頁面還包括該表的一個IAM管理頁面。

  還是透過Internals Viewer外掛讓我們看一下IAM頁的情況吧

2
 

  比較有意思的是SQL Server 2008為什麼不從一開始就為每一個物件分配同一型別的頁面,僅僅是為了節約空間?還是為了與之前版本的相容性?就不得而知了。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/6517/viewspace-677207/,如需轉載,請註明出處,否則將追究法律責任。

相關文章