索引分配映射(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個頁面。
看概念總歸是比較枯燥的,我們可以構建一個具體的例子。
在構建例子之前我們首先需要創建一個把地址轉換為具體頁碼的函數。
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)