zoukankan      html  css  js  c++  java
  • sql 索引笔记--索引组织结构

    非聚集索引与聚集索引具有相同的 B 树结构,它们之间的显著差别在于以下两点:

    • 基础表的数据行不按非聚集键的顺序排序和存储。
    • 非聚集索引的叶层是由索引页而不是由数据页组成。

    既可以使用聚集索引来为表或视图定义非聚集索引,也可以根据堆来定义非聚集索引。非聚集索引中的每个索引行都包含非聚集键值和行定位符。此定位符指向聚集索引或堆中包含该键值的数据行。

    非聚集索引行中的行定位器或是指向行的指针,或是行的聚集索引键,如下所述:

    • 如果表是堆(意味着该表没有聚集索引),则行定位器是指向行的指针。该指针由文件标识符 (ID)、页码和页上的行数生成。整个指针称为行 ID (RID)。
    • 如果表有聚集索引或索引视图上有聚集索引,则行定位器是行的聚集索引键。如果聚集索引不是唯一的索引,SQL Server 2005 将添加在内部生成的值(称为唯一值)以使所有重复键唯一。此四字节的值对于用户不可见。仅当需要使聚集键唯一以用于非聚集索引中时,才添加该值。SQL Server 通过使用存储在非聚集索引的叶行内的聚集索引键搜索聚集索引来检索数据行。

    对于索引使用的每个分区,非聚集索引在 index_id >0 的 sys.partitions 中都有对应的一行。默认情况下,一个非聚集索引有单个分区。如果一个非聚集索引有多个分区,则每个分区都有一个包含该特定分区的索引行的 B 树结构。例如,如果一个非聚集索引有四个分区,那么就有四个 B 树结构,每个分区中一个。

    根据非聚集索引中数据类型的不同,每个非聚集索引结构会有一个或多个分配单元,在其中存储和管理特定分区的数据。每个非聚集索引至少有一个 针对每个分区的 IN_ROW_DATA 分配单元(存储索引 B 树页)。如果非聚集索引包含大型对象 (LOB) 列,则还有一个针对每个分区的 LOB_DATA 分配单元。此外,如果非聚集索引包含的可变长度列超过 8,060 字节行大小限制,则还有一个针对每个分区的 ROW_OVERFLOW_DATA 分配单元。有关分配单元的详细信息,请参阅表组织和索引组织。B 树的页集合由 sys.system_internals_allocation_units 系统视图中的 root_page 指针定位。

    ms177484.note(zh-cn,SQL.90).gif重要提示:
    sys.system_internals_allocation_units 系统视图仅供内部使用,随时可能更改。不保证兼容性。

    下图说明了单个分区中的非聚集索引结构。

    非聚集索引的级别
     

    在 SQL Server 中,索引是按 B 树结构进行组织的。索引 B 树中的每一页称为一个索引节点。B 树的顶端节点称为根节点。索引中的底层节点称为叶节点。根节点与叶节点之间的任何索引级别统称为中间级。在聚集索引中,叶节点包含基础表的数据页。根节点 和中间级节点包含存有索引行的索引页。每个索引行包含一个键值和一个指针,该指针指向 B 树上的某一中间级页或叶级索引中的某个数据行。每级索引中的页均被链接在双向链接列表中。

    聚集索引在 sys.partitions 中有一行,其中,索引使用的每个分区的 index_id = 1。默认情况下,聚集索引有单个分区。当聚集索引有多个分区时,每个分区都有一个包含该特定分区相关数据的 B 树结构。例如,如果聚集索引有四个分区,就有四个 B 树结构,每个分区中有一个 B 树结构。

    根据聚集索引中的数据类型,每个聚集索引结构将有一个或多个分配单元,将在这些单元中存储和管理特定分区的相关数据。每个聚集索引的每个分区中至少 有一个 IN_ROW_DATA 分配单元。如果聚集索引包含大型对象 (LOB) 列,则它的每个分区中还会有一个 LOB_DATA 分配单元。如果聚集索引包含的变量长度列超过 8,060 字节的行大小限制,则它的每个分区中还会有一个 ROW_OVERFLOW_DATA 分配单元。有关分配单元的详细信息,请参阅表组织和索引组织

    数据链内的页和行将按聚集索引键值进行排序。所有插入操作都在所插入行中的键值与现有行中的排序顺序相匹配时执行。B 树页集合由 sys.system_internals_allocation_units 系统视图中的页指针来定位。

    ms177443.note(zh-cn,SQL.90).gif重要提示:
    sys.system_internals_allocation_units 系统视图仅供内部使用,随时可能更改。不保证兼容性。

    对于某个聚集索引,sys.system_internals_allocation_units 中的 root_page 列指向该聚集索引某个特定分区的顶部。SQL Server 将在索引中向下移动以查找与某个聚集索引键对应的行。为了查找键的范围,SQL Server 将在索引中移动以查找该范围的起始键值,然后用向前或向后指针在数据页中进行扫描。为了查找数据页链的首页,SQL Server 将从索引的根节点沿最左边的指针进行扫描。

    下图显式了聚集索引单个分区中的结构。

    聚集索引的级别

    堆是不含聚集索引的表。堆的 sys.partitions 中具有一行,对于堆使用的每个分区,都有 index_id = 0。默认情况下,一个堆有一个分区。当堆有多个分区时,每个分区有一个堆结构,其中包含该特定分区的数据。例如,如果一个堆有四个分区,则有四个堆结构;每个分区有一个堆结构。

    根据堆中的数据类型,每个堆结构将有一个或多个分配单元来存储和管理特定分区的数据。每个堆中的每个分区至少有一个 IN_ROW_DATA 分配单元。如果堆包含大型对象 (LOB) 列,则该堆的每个分区还将有一个 LOB_DATA 分配单元。如果堆包含超过 8,060 字节行大小限制的可变长度列,则该堆的每个分区还将有一个 ROW_OVERFLOW_DATA 分配单元。有关分配单元的详细信息,请参阅表组织和索引组织

    sys.system_internals_allocation_units 系统视图中的列 first_iam_page 指向管理特定分区中堆的分配空间的一系列 IAM 页的第一页。SQL Server 2005 使用 IAM 页在堆中移动。堆内的数据页和行没有任何特定的顺序,也不链接在一起。数据页之间唯一的逻辑连接是记录在 IAM 页内的信息。

    ms188270.note(zh-cn,SQL.90).gif重要提示:
    sys.system_internals_allocation_units 系统视图仅供内部使用,随时可能更改。不保证兼容性。

    可以通过扫描 IAM 页对堆进行表扫描或串行读操作来找到容纳该堆的页的扩展盘区。因为 IAM 按扩展盘区在数据文件内存在的顺序表示它们,所以这意味着串行堆扫描连续沿每个文件进行。使用 IAM 页设置扫描顺序还意味着堆中的行一般不按照插入的顺序返回。

    下图说明 SQL Server 数据库引擎 如何使用 IAM 页检索具有单个分区的堆中的数据行。

    IAM 页从单个分区堆中检索数据
     

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

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

    具有分区的表组织结构

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

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

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

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

    • 聚集表是有聚集索引的表。
      数据行基于聚集索引键按顺序存储。聚集索引按 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

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

    页的类型为 Text/Image。

    ROW_OVERFLOW_DATA

    存储在超过 8,060 字节行大小限制的 varcharnvarcharvarbinarysql_variant 列中的可变长度数据。

    页的类型为 Data。

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

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

    IN_ROW_DATA 分配单元

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

    ms189051.note(zh-cn,SQL.90).gif重要提示:
    sys.system_internals_allocation_units 系统视图仅供内部使用,随时可能更改。不保证兼容性。

    每个表、索引和索引视图分区在 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 分配单元中带有可变长度列(varcharnvarcharvarbinarysql_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 数据类型包括 textntextimagexmlvarchar(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)
    
    用对方法才有效率,做对事情才有效果
    “麻烦”是自己“处理”不当的结果
    “困难”是自己“学习”不够的反射

    “挫折”是自己“努力”不足的代价

  • 相关阅读:
    【原创】R61509/SPFD5420A驱动调试总结
    [轉貼]程序员需要具备的基本技能
    Entity SQL 说说IN关键字
    细说可空类型 nullable
    C#值类型与引用类型之我见
    解密区域集成服务器
    序列化对象,使用的三种方式:Xml,Binary,Soap
    有时间就买点书
    hdu2680 Choose the best route
    SQLServer 函数类型简要说明
  • 原文地址:https://www.cnblogs.com/ly7454/p/3649120.html
Copyright © 2011-2022 走看看