表组织和索引组织

表和索引作为 8 KB 页的集合存储。本主题介绍表页和索引页的组织方式。

表组织

下图显示了表的组织。表包含在一个或多个分区中,每个分区在一个堆或一个聚集索引结构包含数据行。堆页或聚集索引页在一个或多个分配单元中进行管理,具体的分配单元数取决于数据行中的列类型。

具有分区的表组织结构

分区

表页和索引页包含在一个或多个分区中。分区是用户定义的数据组织单元。默认情况下,表或索引只有一个分区,其中包含所有的表页或索引页。该分区驻留在单个文件组中。具有单个分区的表或索引相当于 SQL Server 早期版本中的表和索引的组织结构。

当表或索引使用多个分区时,数据将被水平分区,以便根据指定的列将行组映射到各个分区。分区可以放在数据库中的一个或多个文件组中。对数据进行查询或更新时,表或索引将被视为单个逻辑实体。有关详细信息,请参阅已分区表和已分区索引

若要查看表或索引使用的分区,请使用 sys.partitions (Transact-SQL) 目录视图。

聚集表、堆和索引

SQL Server 表使用下列两种方法之一来组织其分区中的数据页:

  • 聚集表是有聚集索引的表。

    数据行基于聚集索引键按顺序存储。聚集索引按 B 树索引结构实现,B 树索引结构支持基于聚集索引键值对行进行快速检索。索引中每个级别的页(包括叶级别的数据页)链接在一个双向链接的列表中。但是,通过使用键值来执行从一个级别到另一级别的导航。有关详细信息,请参阅聚集索引结构

  • 堆是没有聚集索引的表。

    数据行不按任何特殊的顺序存储,数据页也没有任何特殊的顺序。数据页不在链接列表内链接。有关详细信息,请参阅堆结构

索引视图与聚集表具有相同的存储结构。

当堆或聚集表具有多个分区时,每个分区都有一个堆或 B 树结构,其中包含该指定分区的行组。例如,如果一个聚集表有 4 个分区,那么将有 4 个 B 树,每个分区一个。

非聚集索引

非聚集索引与聚集索引有一个相似的 B 树索引结构。不同的是,非聚集索引不影响数据行的顺序。叶级别包含索引行。每个索引行包含非聚集键值、行定位符和任意包含列或非键列。定位符指向包含键值的数据行。有关详细信息,请参阅非聚集索引结构

XML 索引

可以对表中的每个 xml 列创建一个主 XML 索引和多个辅助 XML 索引。XML 索引是 xml 数据类型列中的 XML 二进制大型对象 (BLOB) 的拆分和持久化的表示形式。XML 索引以内部表的形式存储。若要查看有关 XML 索引的信息,请使用 sys.xml_indexessys.internal_tables 目录视图。

有关 XML 索引的详细信息,请参阅 XML 数据类型列的索引

分配单元

分配单元是堆或 B 树内用于根据页类型管理数据的页集合。下表列出了用于管理表和索引中的数据的分配单元类型。

分配单元类型

用于管理

IN_ROW_DATA

包含除大型对象 (LOB) 数据以外的所有数据的数据行或索引行。

页的类型为 Data 或 Index。

LOB_DATA

以下列一种或多种数据类型存储的大型对象数据:text、ntext、image、xml、varchar(max)、nvarchar(max)、varbinary(max) 或 CLR 用户定义类型 (CLR UDT)。

页的类型为 Text/Image。

ROW_OVERFLOW_DATA

存储在超过 8,060 字节行大小限制的 varchar、nvarchar、varbinary 或 sql_variant 列中的可变长度数据。

页的类型为 Text/Image。

有关页类型的详细信息,请参阅页和区

在堆或 B 树的特定分区中,每种类型只能有一个分配单元。若要查看表或索引的分配单元信息,请使用 sys.allocation_units 目录视图。

IN_ROW_DATA 分配单元

对于表(堆或聚集表)、索引或索引视图使用的每个分区,只有一个 IN_ROW_DATA 分配单元,它由一个数据页集合构成。此分配单元还包含其他页集合,这些集合用来实现为表或视图定义的每个非聚集索引和 XML 索引。表、索引或索引视图的每个分区中的页集合由 sys.system_internals_allocation_units 系统视图中的页指针定位。

重要说明重要提示

sys.system_internals_allocation_units 系统视图保留为仅供 MicrosoftSQL Server 内部使用。不保证将来的兼容性。

每个表、索引和索引视图分区在 sys.system_internals_allocation_units 中有一行,该行由容器 ID (container_id) 唯一标识。容器 ID 与 sys.partitions 目录视图中的 partition_id 之间具有一对一的映射,用于维护分区中存储的表、索引或索引视图数据与用来管理分区内数据的分配单元之间的关系。

表、索引或索引视图分区的页分配由一个 IAM 页链管理。sys.system_internals_allocation_units 中的 first_iam_page 列指向 IAM 页链(用于管理分配给 IN_ROW_DATA 分配单元中的表、索引或索引视图的空间)中的第一个 IAM 页。

sys.partitions 为表或索引中每个分区返回一行。

  • 堆在 sys.partitions 中有一行,其 index_id = 0。

    sys.system_internals_allocation_units 中的 first_iam_page 列指向指定分区中堆数据页集合的 IAM 链。服务器使用 IAM 页查找数据页集合中的页,因为这些页没有链接。

  • 表或视图的聚集索引在 sys.partitions 中有一行,其 index_id = 1。

    sys.system_internals_allocation_units 中的 root_page 列指向指定分区内聚集索引 B 树的顶端。服务器使用索引 B 树查找分区中的数据页。

  • 为表或视图创建的每个非聚集索引在 sys.partitions 中有一行,其 index_id > 1。

    sys.system_internals_allocation_units 中的 root_page 列指向指定分区内非聚集索引 B 树的顶端。

  • 至少有一个 LOB 列的每个表在 sys.partitions 中也有一行,其 index_id > 250。

    first_iam_page 列指向管理 LOB_DATA 分配单元中的页的 IAM 页链。

ROW_OVERFLOW_DATA 分配单元

对于表(堆或聚集表)、索引或索引视图使用的每个分区,都有一个 ROW_OVERFLOW_DATA 分配单元。此分配单元包含零 (0) 页,直到 IN_ROW_DATA 分配单元中带有可变长度列(varchar、nvarchar、varbinary 或 sql_variant)的数据行超过 8 KB 的行大小限制。达到大小限制后,SQL Server 将把最宽的列从该行移动到 ROW_OVERFLOW_DATA 分配单元中的页。原始页上将维护一个指向此行外数据的 24 字节指针。

ROW_OVERFLOW_DATA 分配单元中 Text/Image 页的管理方式与 LOB_DATA 分配单元中页的管理方式相同。即,使用 IAM 页链管理 Text/Image 页。

LOB_DATA 分配单元

当表或索引有一个或多个 LOB 数据类型时,将为每个分区分配一个 LOB_DATA 分配单元,以管理该数据的存储。LOB 数据类型包括 text、ntext、image、xml、varchar(max)、nvarchar(max)、varbinary(max) 和 CLR 用户定义类型。

分区和分配单元示例

下列示例返回两个表的分区和分配单元数据:DatabaseLog,具有 LOB 数据但没有非聚集索引的堆;Currency,没有 LOB 数据但有一个非聚集索引的聚集表。两个表都有一个分区。

USE AdventureWorks;
GO
SELECT o.name AS table_name,p.index_id, i.name AS index_name , au.type_desc AS allocation_type, au.data_pages, partition_number
FROM sys.allocation_units AS au
    JOIN sys.partitions AS p ON au.container_id = p.partition_id
    JOIN sys.objects AS o ON p.object_id = o.object_id
    JOIN sys.indexes AS i ON p.index_id = i.index_id AND i.object_id = p.object_id
WHERE o.name = N'DatabaseLog' OR o.name = N'Currency'
ORDER BY o.name, p.index_id;

下面是结果集。请注意,DatabaseLog 表使用所有三个分配单元类型,因为表中包含 Data 和 Text/Image 页类型。Currency 表没有 LOB 数据,但具有管理数据页所需的分配单元。如果以后将 Currency 表修改为包含 LOB 数据类型列,将创建一个 LOB_DATA 分配单元来管理该数据。

table_name  index_id index_name               allocation_type     data_pages  partition_number 
----------- -------- -----------------------  ---------------     -----------  ------------
Currency    1        PK_Currency_CurrencyCode IN_ROW_DATA         1           1
Currency    3        AK_Currency_Name         IN_ROW_DATA         1           1
DatabaseLog 0        NULL                     IN_ROW_DATA         160         1
DatabaseLog 0        NULL                     ROW_OVERFLOW_DATA   0           1
DatabaseLog 0        NULL                     LOB_DATA            49          1
(5 row(s) affected)