内部表

SQL Server 将自动创建内部表以支持下列功能:

  • 主 XML 索引

  • 空间索引

  • Service Broker

  • 查询通知

  • 更改跟踪

内部表是某些其他用户操作所产生的副产品。 例如,创建主 XML 索引时,SQL Server 将自动创建一个内部表以保存拆分的 XML 文档数据。 内部表出现在每个数据库的 sys 架构中,具有指示其功能的由系统生成的专有名称,例如 xml_index_nodes_2021582240_32001queue_messages_1977058079

内部表不包括用户可访问的数据,并且其架构是固定的,不可改变。 不能在 Transact-SQL 语句中引用内部表名称。 例如,不能执行 SELECT * FROM <sys.internal_table_name> 之类的语句。 但是,可以查询目录视图以查看内部表的元数据。

查看内部表元数据

使用 sys.internal_tables 目录视图,可以查看与内部表关联的元数据。 使用此视图,可以查看内部表的架构。 由于内部表与用户表具有许多相同的特征,因此 sys.internal_tables 视图继承了 sys.objects 目录视图中的列,并具有类型“IT”。 与用户表一样,可以在 sys.columns 目录视图中查看内部表的列元数据,在 sys.indexessys.stats 目录视图中查看内部表的由系统生成的索引和统计信息的元数据。

通过联接到其他目录视图,还可以获取有关分配和空间利用率的信息。 请参阅本主题后面的“内部表存储”。

下图显示了顶级目录数据模型。

内部表目录视图的关系图

查看内部表元数据的权限

若要查看数据库的内部表元数据,您需要具有下列一种权限和组成员身份:

  • CONTROL SERVER 权限。

  • 数据库中的 CONTROL 权限。

  • db_ownersysadmin 组中的成员身份。

  • 可以查看父实体(XML 索引、空间索引或队列)的用户可以查看此实体的内部表。

查看 XML 索引元数据

下图显示了 XML 索引内部表的元数据结构。

XML 索引目录视图的关系图

为了理解图中所示的目录视图关系,假设对表 T 创建了主 XML 索引 Xp。 此表的元数据位于 sys.tables 目录视图中,XML 索引的元数据位于 sys.xml_indexes 目录视图中。 SQL Server 创建以保存 XML 索引数据的内部表 Ti 的元数据位于 sys.internal_tables 视图中。

若要查找内部表 Ti 和用户表 T 之间的关系,可以将 sys.internal_tables 视图的 parent_id 列联接到 sys.tables 视图的 object_id 列。 若要查找内部表 Ti 和 XML 索引 Xp 之间的关系,可以将 sys.internal_tablesparent_idparent_minor_id 列联接到 sys.xml_indexesobject_idindex_id 列。 请参阅下面的示例 G。

查看空间索引元数据

空间索引的元数据与 XML 索引的元数据大部分相同。 区别在于空间索引使用 sys.spatial_indexes 而非 sys.xml_indexes,并且您需要使用 sys.spatial_index_tessellations 才能查看空间索引的空间参数。

下图显示了空间索引内部表的元数据结构。

空间索引目录视图的关系图

为了理解图中所示的目录视图关系,假设对表 T 创建了空间索引 Si。 此表的元数据位于 sys.tables 目录视图中,空间索引的元数据位于 sys.spatial_indexes 目录视图和 sys.spatial_index_tessellations 目录视图中。 SQL Server 为保存空间索引数据而创建的内部表 Ti 的元数据位于 sys.internal_tables 视图中。

若要查找内部表 Ti 和用户表 T 之间的关系,可以将 sys.internal_tables 视图的 parent_id 列联接到 sys.tables 视图的 object_id 列。 若要查找内部表 Ti 和空间索引 Si 之间的关系,可以将 sys.internal_tablesparent_idparent_minor_id 列联接到 sys.spatial_indexesobject_idindex_id 列。 有关详细信息,请参阅本主题后面的示例 L。

查看 Service Broker 元数据

下图显示了 Service Broker 队列内部表的元数据结构。 Service Broker 消息、查询通知和事件通知都使用 Service Broker 队列。 此外,Service Broker 功能还使用内部表存储有关所有数据库中的所有 Service Broker 服务的信息。 此内部表位于 tempdb 系统数据库中。

Service Broker 目录视图的关系图

查看查询通知元数据

下图显示了查询通知订阅内部表的元数据结构。 内部表用于存储查询通知订阅的参数。

查询通知目录视图的关系图

内部表存储

内部表与父实体位于同一文件组。 可以使用下面示例 F 中所示的目录查询返回内部表中用于行内数据、行外数据和大型对象 (LOB) 数据的页数。

可以使用 sp_spaceused 系统过程返回内部表的空间使用情况数据。sp_spaceused 以下列方式报告内部表空间:

  • 当指定队列名称时,将引用与队列关联的基础内部表并报告其存储空间使用情况。

  • XML 索引、空间索引和全文索引的内部表所使用的页包括在 index_size 列中。 当指定表或索引视图名称时,此对象的 XML 索引、空间索引和全文索引的页包括在 reservedindex_size 列中。

示例

下列示例说明如何使用目录视图查询内部表元数据。

A. 显示继承 sys.objects 目录视图中的列的内部表

SELECT * FROM sys.objects WHERE type = 'IT';

B. 返回所有内部表元数据(包括从 sys.objects 中继承的元数据)

SELECT * FROM sys.internal_tables;

C. 返回内部表列和列数据类型

SELECT SCHEMA_NAME(itab.schema_id) AS schema_name
    ,itab.name AS internal_table_name
    ,typ.name AS column_data_type 
    ,col.*
FROM sys.internal_tables AS itab
JOIN sys.columns AS col ON itab.object_id = col.object_id
JOIN sys.types AS typ ON typ.user_type_id = col.user_type_id
ORDER BY itab.name, col.column_id;

D. 返回内部表索引

SELECT SCHEMA_NAME(itab.schema_id) AS schema_name
    , itab.name AS internal_table_name
    , idx.*
FROM sys.internal_tables AS itab
JOIN sys.indexes AS idx ON itab.object_id = idx.object_id
ORDER BY itab.name, idx.index_id;

E. 返回内部表统计信息

SELECT SCHEMA_NAME(itab.schema_id) AS schema_name
    ,itab.name AS internal_table_name
    , s.*
FROM sys.internal_tables AS itab
JOIN sys.stats AS s ON itab.object_id = s.object_id
ORDER BY itab.name, s.stats_id;

F. 返回内部表分区和分配单元信息

SELECT SCHEMA_NAME(itab.schema_id) AS schema_name
    ,itab.name AS internal_table_name
    ,idx.name AS heap_or_index_name
    ,p.*
    ,au.*
FROM sys.internal_tables AS itab
JOIN sys.indexes AS idx
--     JOIN to the heap or the clustered index
    ON itab.object_id = idx.object_id AND idx.index_id IN (0,1)
JOIN   sys.partitions AS p 
    ON p.object_id = idx.object_id AND p.index_id = idx.index_id
JOIN   sys.allocation_units AS au
--     IN_ROW_DATA (type 1) and ROW_OVERFLOW_DATA (type 3) => JOIN to partition's Hobt
--     else LOB_DATA (type 2) => JOIN to the partition ID itself.
ON au.container_id =  
    CASE au.type 
        WHEN 2 THEN p.partition_id 
        ELSE p.hobt_id 
    END
ORDER BY itab.name, idx.index_id;

G. 返回 XML 索引的内部表元数据

SELECT t.name AS parent_table
    ,t.object_id AS parent_table_id
    ,it.name AS internal_table_name
    ,it.object_id AS internal_table_id
    ,xi.name AS primary_XML_index_name
    ,xi.index_id as primary_XML_index_id
FROM sys.internal_tables AS it
JOIN sys.tables AS t 
    ON it.parent_id = t.object_id
JOIN sys.xml_indexes AS xi 
    ON it.parent_id = xi.object_id
    AND it.parent_minor_id  = xi.index_id
WHERE it.internal_type_desc = 'XML_INDEX_NODES';
GO

H. 返回 Service Broker 队列的内部表元数据

SELECT q.name AS queue_name
    ,q.object_id AS queue_id
    ,it.name AS internal_table_name
    ,it.object_id AS internal_table_id
FROM sys.internal_tables AS it
JOIN sys.service_queues  AS  q ON it.parent_id = q.object_id
WHERE it.internal_type_desc = 'QUEUE_MESSAGES';
GO

I. 返回所有 Service Broker 服务的内部表元数据

SELECT * 
FROM tempdb.sys.internal_tables 
WHERE internal_type_desc = 'SERVICE_BROKER_MAP';
GO

J. 返回查询通知订阅的内部表元数据

SELECT qn.id AS query_subscription_id
    ,it.name AS internal_table_name
    ,it.object_id AS internal_table_id
FROM sys.internal_tables AS it
JOIN sys.dm_qn_subscriptions AS qn ON it.object_id = qn.object_id
WHERE it.internal_type_desc = 'QUERY_NOTIFICATION';

K. 返回空间索引的内部表元数据

SELECT t.name AS parent_table
    ,t.object_id AS parent_table_id
    ,it.name AS internal_table_name
    ,it.object_id AS internal_table_id
    ,si.name AS spatial_index_name
    ,si.index_id as spatial_index_id
FROM sys.internal_tables AS it
JOIN sys.tables AS t 
    ON it.parent_id = t.object_id
JOIN sys.spatial_indexes AS si 
    ON it.parent_id = si.object_id
    AND it.parent_minor_id  = si.index_id
WHERE it.internal_type_desc = 'EXTENDED_INDEXES';
GO