关于SQL Server:集群索引和非集群索引实际上意味着什么?

What do Clustered and Non clustered index actually mean?

我对数据库的接触有限,只使用数据库作为应用程序程序员。我想知道关于ClusteredNon clustered indexes。我搜索了一下,发现:

A clustered index is a special type of index that reorders the way
records in the table are physically
stored. Therefore table can have only
one clustered index. The leaf nodes
of a clustered index contain the data
pages. A nonclustered index is a
special type of index in which the
logical order of the index does not
match the physical stored order of
the rows on disk. The leaf node of a
nonclustered index does not consist of
the data pages. Instead, the leaf
nodes contain index rows.

我在So中发现的是聚集索引和非聚集索引之间的区别是什么?.

有人能用简单的英语解释吗?


使用聚集索引,行以与索引相同的顺序物理存储在磁盘上。因此,只能有一个聚集索引。

对于非聚集索引,第二个列表具有指向物理行的指针。您可以拥有许多非聚集索引,尽管每个新索引都会增加写入新记录所需的时间。

如果希望返回所有列,则从聚集索引中读取通常更快。您不必先转到索引,然后再转到表。

如果需要重新排列数据,则使用聚集索引写入表的速度可能会较慢。


聚集索引意味着您要告诉数据库在磁盘上存储彼此接近的关闭值。这有利于快速扫描/检索属于某个聚集索引值范围的记录。

例如,您有两个表,客户和订单:

1
2
3
4
5
6
7
8
9
10
11
Customer
----------
ID
Name
Address

Order
----------
ID
CustomerID
Price

如果希望快速检索某个特定客户的所有订单,则可能希望在订单表的"customerid"列上创建聚集索引。这样,具有相同customerid的记录将物理上存储在磁盘(群集)上,从而加快检索速度。

另外,customerid上的索引显然不是唯一的,所以您要么需要添加第二个字段来"统一"索引,要么让数据库为您处理索引,但这是另一个情况。

关于多个索引。每个表只能有一个聚集索引,因为这定义了数据的物理排列方式。如果你想做一个类比,想象一下一个有很多桌子的大房间。您可以将这些表放在一起形成几行,或者将它们全部拉到一起形成一个大型会议桌,但不能同时以两种方式进行。一个表可以有其他索引,然后它们将指向聚集索引中的条目,而聚集索引又将最终指出在何处查找实际数据。


在SQL Server面向行的存储中,聚集索引和非聚集索引都被组织为B树。好的。

enter image description here好的。

(图像源)好的。

聚集索引和非聚集索引的关键区别在于聚集索引的叶级是表。这有两个含义。好的。

  • 聚集索引叶页上的行始终包含表中每个(非稀疏)列的内容(值或指向实际值的指针)。
  • 聚集索引是表的主副本。
  • 非聚集索引也可以通过使用INCLUDE子句(自SQL Server 2005以来)显式地包括所有非键列来完成点1,但它们是辅助表示,并且始终有数据的另一个副本(表本身)。好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    CREATE TABLE T
    (
    A INT,
    B INT,
    C INT,
    D INT
    )

    CREATE UNIQUE CLUSTERED INDEX ci ON T(A,B)
    CREATE UNIQUE NONCLUSTERED INDEX nci ON T(A,B) INCLUDE (C,D)

    上面的两个索引将几乎相同。其中上层索引页包含键列A,B的值,叶级页包含A,B,C,D的值。好的。

    There can be only one clustered index per table, because the data rows
    themselves can be sorted in only one order.

    Ok.

    上面引用的来自SQL Server联机丛书的话会引起很多混乱好的。

    在我看来,它的措辞会更好一些。好的。

    There can be only one clustered index per table, because the leaf level rows of the clustered index are the table rows.

    Ok.

    联机丛书的引用并不错误,但您应该清楚,非聚集索引和聚集索引的"排序"都是逻辑的,而不是物理的。如果您按照链接列表读取叶级的页,并按槽数组顺序读取页上的行,那么您将按排序顺序读取索引行,但在物理上可能不会对页进行排序。对于聚集索引,通常认为行总是以与索引键相同的顺序物理存储在磁盘上是错误的。好的。

    这将是一个荒谬的实现。例如,如果一行插入到4GB表的中间,则SQL Server不必在文件中向上复制2GB数据,以便为新插入的行腾出空间。好的。

    相反,会发生页面拆分。在聚集索引和非聚集索引的叶级上的每个页面都有逻辑键顺序的下一页和上一页的地址(File:Page)。这些页面不需要是连续的,也不需要按键顺序。好的。

    例如,链接的页面链可能是1:2000 <-> 1:157 <-> 1:7053。好的。

    当发生页拆分时,将从文件组中的任何位置(从混合区、小表、属于该对象的非空统一区或新分配的统一区)分配新页。如果文件组包含多个文件,则它甚至可能不在同一个文件中。好的。

    逻辑顺序和连续性不同于理想的物理版本的程度是逻辑碎片的程度。好的。

    在一个新创建的带有单个文件的数据库中,我运行了以下命令。好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    CREATE TABLE T
      (
         X TINYINT NOT NULL,
         Y CHAR(3000) NULL
      );

    CREATE CLUSTERED INDEX ix
      ON T(X);

    GO

    --Insert 100 rows with values 1 - 100 in random order
    DECLARE @C1 AS CURSOR,
            @X  AS INT

    SET @C1 = CURSOR FAST_FORWARD
    FOR SELECT number
        FROM   master..spt_values
        WHERE  type = 'P'
               AND number BETWEEN 1 AND 100
        ORDER  BY CRYPT_GEN_RANDOM(4)

    OPEN @C1;

    FETCH NEXT FROM @C1 INTO @X;

    WHILE @@FETCH_STATUS = 0
      BEGIN
          INSERT INTO T (X)
          VALUES        (@X);

          FETCH NEXT FROM @C1 INTO @X;
      END

    然后检查页面布局好的。

    1
    2
    3
    4
    5
    6
    SELECT page_id,
           X,
           geometry::Point(page_id, X, 0).STBuffer(1)
    FROM   T
           CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )
    ORDER  BY page_id

    结果到处都是。键顺序的第一行(值为1-下面的箭头突出显示)几乎位于最后一个物理页上。好的。

    enter image description here好的。

    通过重建或重组索引来增加逻辑顺序和物理顺序之间的相关性,可以减少或删除碎片。好的。

    运行后好的。

    1
    ALTER INDEX ix ON T REBUILD;

    我有以下信息好的。

    enter image description here好的。

    如果表没有聚集索引,则称为堆。好的。

    非聚集索引可以建立在堆或聚集索引上。它们始终包含返回基表的行定位器。对于堆,这是一个物理行标识符(RID),由三个组件(文件:page:slot)组成。对于聚集索引,行定位器是逻辑的(聚集索引键)。好的。

    对于后一种情况,如果非聚集索引已经自然地将CI键列包括为NCI键列或INCLUDEd列,则不添加任何内容。否则,丢失的CI键列将自动添加到NCI中。好的。

    SQL Server始终确保两种索引类型的键列都是唯一的。但是,对未声明为唯一的索引强制执行此操作的机制在两种索引类型之间有所不同。好的。

    聚集索引为任何具有复制现有行的键值的行添加一个uniquifier。这只是一个升序整数。好的。

    对于未声明为唯一SQL Server的非聚集索引,将行定位器自动添加到非聚集索引键中。这适用于所有行,而不仅仅是那些实际重复的行。好的。

    集群与非集群术语也用于列存储索引。SQL Server列的纸张增强功能存储状态好的。

    Although column store data is not really"clustered" on any key, we
    decided to retain the traditional SQL Server convention of referring
    to the primary index as a clustered index.

    Ok.

    好啊。


    我意识到这是一个非常古老的问题,但我想我会提供一个类比来帮助说明上面的好答案。

    聚集索引

    如果你走进一个公共图书馆,你会发现所有的书都是按特定的顺序排列的(很可能是杜威十进制,或称DDS)。这与书籍的"聚集索引"相对应。如果你想要的书的dds是005.7565 F736s,你可以从找到标有001-099或类似的书架开始。(堆栈末尾的这个端盖符号对应于索引中的一个"中间节点")最后,您将向下钻取到标记为005.7450 - 005.7600的特定书架,然后扫描,直到找到带有指定dds的书,此时您已经找到了您的书。

    非聚集索引

    但是如果你没有带着你的书的DDS进入图书馆,那么你需要第二个索引来帮助你。在过去的日子里,你会在图书馆前面发现一个很棒的抽屉,叫做"卡片目录"。其中有数千张3x5卡片——每本书一张,按字母顺序排序(也许按标题)。这对应于"非聚集索引"。这些卡片目录被组织成一个层次结构,这样每个抽屉都会被标记上它所包含的卡片的范围(例如Ka - Kl;即"中间节点")。再一次,你会钻取直到你找到你的书,但在这种情况下,一旦你找到它(即"叶节点"),你就没有书本身,而是只有一张带有索引号(dds)的卡片,你可以用它在聚集索引中找到真正的书。

    当然,没有什么能阻止图书管理员将所有的卡片影印出来,并将它们按不同的顺序分类到一个单独的卡片目录中。(通常至少有两个这样的目录:一个按作者姓名排序,另一个按标题排序。)原则上,您可以拥有任意多的这些"非聚集"索引。


    以下是聚集索引和非聚集索引的一些特征:

    聚集索引

  • 聚集索引是唯一标识SQL表中行的索引。
  • 每个表只能有一个聚集索引。
  • 可以创建覆盖多个列的聚集索引。例如:create Index index_name(col1, col2, col.....)
  • 默认情况下,具有主键的列已经具有聚集索引。
  • 非聚集索引

  • 非聚集索引类似于简单索引。它们只是用来快速检索数据。不一定有唯一的数据。

  • 一个非常简单的非技术性经验法则是,聚集索引通常用于主键(或者至少是唯一列),而非聚集索引用于其他情况(可能是外键)。实际上,默认情况下,SQL Server将在主键列上创建聚集索引。正如您将了解到的,聚集索引与数据在磁盘上物理排序的方式有关,这意味着对于大多数情况来说,它是一个很好的全面选择。


    聚集索引

    聚集索引决定表中数据的物理顺序。因此,表只有1个聚集索引。

    就像"字典"不需要任何其他索引,它已经根据单词索引

    非凑集索引

    非聚集索引类似于书中的索引,数据存储在一个地方。这个索引存储在另一个位置,并且索引具有指向数据存储位置的指针。因此,表具有多个非聚集索引。

    像《化学书》一样,盯着看有一个单独的索引指向章节的位置,而在"结尾"则有另一个索引指向常用词的位置。


    聚集索引

    聚集索引根据数据行的键值对表或视图中的数据行进行排序和存储。这些是索引定义中包含的列。每个表只能有一个聚集索引,因为数据行本身只能按一个顺序排序。

    表中数据行按排序顺序存储的唯一时间是表包含聚集索引时。当表具有聚集索引时,该表称为聚集表。如果表没有聚集索引,则其数据行存储在称为堆的无序结构中。

    非聚集的

    非聚集索引具有与数据行分离的结构。非聚集索引包含非聚集索引键值,每个键值条目都有指向包含键值的数据行的指针。从非聚集索引中的索引行指向数据行的指针称为行定位器。行定位器的结构取决于数据页是存储在堆中还是存储在聚集表中。对于堆,行定位器是指向行的指针。对于聚集表,行定位器是聚集索引键。

    可以将非键列添加到非聚集索引的叶级,以绕过现有索引键限制,并执行完全覆盖、索引的查询。有关详细信息,请参阅创建包含列的索引。有关索引键限制的详细信息,请参阅SQL Server的最大容量规范。

    参考:https://docs.microsoft.com/en-us/sql/relational-databases/indexes/clustered-and-nonclustered-indexes-described


    聚集索引:如果表上没有聚集索引,主键约束将自动创建聚集索引。聚集索引的实际数据可以存储在索引的叶级。

    非聚集索引:非聚集索引的实际数据不是直接在叶节点上找到的,而是需要采取额外的步骤来查找,因为它只有指向实际数据的行定位器的值。非聚集索引不能排序为聚集索引。每个表可以有多个非聚集索引,实际上这取决于我们使用的SQL Server版本。基本上,SQL Server 2005允许249个非聚集索引,对于上述版本(如2008、2016),它允许每个表有999个非聚集索引。


    让我提供一个关于"集群索引"的教科书定义,它取自数据库系统的15.6.1:整本书:

    We may also speak of clustering indexes, which are indexes on an attribute or attributes such that all of tuples with a fixed value for the search key of this index appear on roughly as few blocks as can hold them.

    为了理解这个定义,让我们看一下教科书提供的示例15.10:

    A relation R(a,b) that is sorted on attribute a and stored in that
    order, packed into blocks, is surely clusterd. An index on a is a
    clustering index, since for a given a-value a1, all the tuples with
    that value for a are consecutive. They thus appear packed into
    blocks, execept possibly for the first and last blocks that contain
    a-value a1, as suggested in Fig.15.14. However, an index on b is
    unlikely to be clustering, since the tuples with a fixed b-value
    will be spread all over the file unless the values of a and b are
    very closely correlated.

    Fig 15.14

    注意,定义并不强制数据块必须在磁盘上是连续的;它只表示具有搜索键的元组被打包到尽可能少的数据块中。

    一个相关的概念是集群关系。如果一个关系的元组被打包成尽可能少的块,那么这个关系就是"聚集"的。换句话说,从磁盘块的角度来看,如果它包含来自不同关系的元组,那么这些关系就不能被聚集(即,有一种更打包的方法来存储这种关系,方法是将该关系的元组从其他磁盘块替换为不属于当前磁盘块中的关系的元组)。显然,上面示例中的R(a,b)是集群的。

    为了将两个概念连接在一起,聚集关系可以有聚集索引和非聚集索引。但是,对于非聚集关系,除非索引建立在关系的主键之上,否则不可能建立聚集索引。

    "cluster"作为一个词,在数据库存储端的所有抽象级别(三个抽象级别:元组、块、文件)中都会出现。一个称为"集群文件"的概念,它描述一个文件(一组块(一个或多个磁盘块)的抽象)是否包含来自一个关系或不同关系的元组。它与集群索引概念不相关,因为它是在文件级别上的。

    然而,有些教材喜欢根据聚类文件定义来定义聚类索引。这两种定义在集群关系级别上是相同的,不管它们是用数据磁盘块还是文件定义集群关系。从本段的链接中,

    An index on attribute(s) A on a file is a clustering index when: All tuples with attribute value A = a are stored sequentially (= consecutively) in the data file

    连续存储元组与"元组被压缩到尽可能少的块中以容纳这些元组"的说法相同(一个关于文件,另一个关于磁盘)。这是因为连续存储元组是实现"打包到尽可能少的块中以容纳这些元组"的方法。