堆数据表是没有聚集索引的表。即数据行不按任何特殊的顺序存储,数据页也没有任何特殊的顺序。数据页不在链接列表内链接。 sys.system_internals_allocation_units 系统视图中的列 first_iam_page 指向管理特定分区中堆的分配空间的一系列 IAM 页的第一页。SQL Server 使用 IAM 页在堆中移动。堆内的数据页和行没有任何特定的顺序,也不链接在一起。数据页之间唯一的逻辑连接是记录在 IAM 页内的信息。
那么堆表是如何存储数据的呢?出于简化的目的,我们先来构造不含任何索引的一张堆数据表,然后从简单到复杂逐步深入探讨。
--创建一张数据表,从系统表生成测试数据
DROP TABLE testheap
--创建一张2个固定长度字段,3个不定长字段的表,其中4个不为空,1个可为空
CREATE TABLE testheap
(
ID INT IDENTITY(1,1) NOT NULL,
name VARCHAR(20) NOT NULL,
type CHAR(100) NOT NULL,
other VARCHAR(50) NOT NULL,
describle VARCHAR(500)
)
--产生1000条随机数据,并插入表中
DECLARE @i INT
SET @i=1
WHILE @i<=1000
BEGIN
INSERT INTO testheap(name,type,other,describle)
VALUES('name'+CAST(@i AS VARCHAR(3)),REPLICATE(@i%4,100),FLOOR(RAND()*10),NULL)
SET @i=@i+1
END
SELECT * FROM testheap
--查询该表的IAM页面地址和首页地址
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 ('testheap')))
查询结果如下:
total_pages | used_pages | data_pages | first_page_address | root_address | IAM_address |
25 | 18 | 17 | 1:224 | 0:0 | 1:119 |
即SQL Server为该表分配了总计25个页面,实际使用了18个页面,扣除1个IAM管理页面,实际数据页面为17个,IAM管理页面地址为第一个文件的第119页面,数据页面的第一个页面为第一个文件的第224页面。
那么如何查看到该表的页面详细分配情况呢?
首先通过dbcc page(testdb,1,119,3)可以粗略看到页面分配情况
即SQL Server首先分配了8个混合区页面,其次因为该对象已经超过8页,SQL Server又分配了从第472页到第487页的页面,共计16个页面,然后包括本身的IAM页面,共计25个页面。