聚簇索引和非聚簇索引实际上是什么意思?


1116

我对DB的接触有限,只使用DB作为应用程序程序员。我想知道ClusteredNon clustered indexes。我用谷歌搜索,发现的是:

聚集索引是一种特殊的索引,它重新排序表中记录的物理存储方式。因此,表只能有一个聚集索引。聚集索引的叶节点包含数据页。非聚集索引是一种特殊类型的索引,其中索引的逻辑顺序与磁盘上行的物理存储顺序不匹配。非聚集索引的叶节点不包含数据页。相反,叶节点包含索引行。

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

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

Answers:


1115

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

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

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

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


43
您应该澄清“物理上”的意思。
斯宾塞·鲁波特

141
物理上与存储在磁盘上的实际位相同
Peter

17
请参阅msdn, “当您创建PRIMARY KEY约束时,如果表上的聚簇索引不存在,则会在一个或多个列上自动创建一个唯一的聚簇索引”,这意味着不必必须是同一列。

46
@Pete并非如此。SQL Server当然不能保证所有数据文件都放置在磁盘的连续物理区域中,并且文件系统碎片为零。甚至在数据文件中按顺序排列聚集索引也不是正确的。并非如此的程度是逻辑碎片的程度。
马丁·史密斯

42
请快速评论一下以支持Martin Smith的观点-聚集索引不能保证磁盘上的顺序存储。确切地管理数据在磁盘上的位置是操作系统的任务,而不是DBMS的任务。但是它建议项目通常根据聚类键排序。这意味着,例如,如果数据库增长了10GB,则操作系统可能决定将10GB分成5x2GB的块放入磁盘的不同部分。覆盖10GB的群集表将按顺序存储在每个2GB块上,但是这些2GB块可能不是顺序的。
2013年

601

聚集索引意味着您要告诉数据库在磁盘上存储实际上彼此接近的关闭值。这具有快速扫描/检索落入聚集索引值范围内的记录的好处。

例如,您有两个表Customer和Order:

Customer
----------
ID
Name
Address

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

如果希望快速检索一个特定客户的所有订单,则可能希望在“订单”表的“ CustomerID”列上创建聚簇索引。这样,具有相同CustomerID的记录将在物理上彼此靠近存储(聚集)在磁盘上,从而加快了检索速度。

PS客户ID上的索引显然不是唯一的,因此您要么需要添加第二个字段来“唯一化”索引,要么让数据库为您处理该索引,但这是另一回事了。

关于多个索引。每个表只能有一个聚集索引,因为它定义了数据的物理排列方式。如果您想打个比方,请想象一个有很多桌子的大房间。您可以将这些表形成几行,也可以将它们全部拉在一起以形成一个大会议表,但不能同时使用两种方法。一个表可以有其他索引,它们将指向聚集索引中的条目,而聚集索引又将最终说出在哪里可以找到实际数据。


4
话虽如此,CI应该始终用于PK
mko 2013年

4
因此,对于聚集索引,是索引或表中存储紧密的记录吗?
卡托2014年

5
@Caltor 表。索引按定义排序。例如,将对btree进行排序,以便可以简单地执行地址算术进行搜索。集群的想法是为了使表适应特定索引的性能。为了清楚起见,该表的记录将重新排序以匹配索引最初所在的顺序。
FLGMwt 2014年

9
@Caltor一点都不!确实,文档和名称本身具有很大的误导性。拥有“聚集索引”确实与索引没有多大关系。从概念上讲,您真正拥有的是“聚集在索引x上的表”。
FLGMwt 2014年

3
@JohnOrtizOrdoñez:当然,你可以几乎所有的使用储存在行的,所以没有XMLVARCHAR(MAX)VARBINARY(MAX)。请注意,通常首先在日期字段上聚类是有意义的,因为聚类索引对于范围扫描最为有效,而范围扫描在日期类型上最为常见。YMMV。

317

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

在此处输入图片说明

图片来源

聚集索引和非聚集索引之间的主要区别在于,聚集索引的叶级表。这有两个含义。

  1. 聚集索引叶页上的行始终为表中的每个(非稀疏)列包含某些内容(值或指向实际值的指针)。
  2. 聚集索引是表的主副本。

非聚集索引也可以通过使用INCLUDE子句(自SQL Server 2005开始)明确包含所有非键列来进行第1点的操作,但是它们是辅助表示,并且周围始终存在数据的另一个副本(表本身)。

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

每个表只能有一个聚集索引,因为数据行本身只能以一种顺序排序。

上面SQL Server在线丛书中的引用引起很多混乱

我认为最好用这样的措辞。

每个表只能有一个聚集索引,因为聚集索引的叶级行表行。

联机丛书的报价并不正确,但是您应该清楚非聚集索引和聚集索引的“排序”是逻辑上而非物理上的。如果您通过遵循链接列表来读取叶级页面,并以插槽数组顺序读取页面上的行,则您将以排序的顺序读取索引行,但实际上页面可能未排序。通常认为,使用聚集索引时,行总是以与索引相同的顺序物理存储在磁盘上,这是错误的。

这将是荒谬的实现。例如,如果某行插入到4GB桌子中间的SQL Server并没有在文件中都有数据的复制2GB高达腾出空间给新插入的行。

而是发生页面拆分。聚簇索引和非聚簇索引的叶级上的每个页面都有File:Page按逻辑键顺序排列的下一页和上一页的地址()。这些页面不必是连续的或按键顺序排列的。

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

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

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

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

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

然后使用

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-用下面的箭头突出显示)几乎在最后一个物理页面上。

在此处输入图片说明

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

跑步后

ALTER INDEX ix ON T REBUILD;

我得到以下

在此处输入图片说明

如果表没有聚簇索引,则称为堆。

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

对于后一种情况,如果非聚簇索引已经自然包含CI键列(作为NCI键列或INCLUDE-d列),则不添加任何内容。否则,缺少的CI键列将被静默添加到NCI中。

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

聚集索引uniquifier将为键值与现有行重复的任何行添加一个。这只是一个递增的整数。

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

聚类命名法与非聚类命名法也用于列存储索引。本文对SQL Server列存储的增强状态

尽管列存储数据并没有真正“聚集”在任何键上,但我们还是决定保留传统的SQL Server约定,即将主索引称为聚簇索引。


8
@brainstorm是的,我知道这一点。可能是由于该MSDN页面上的措词,但是要看到那里的措词有些误导,您只需要查看碎片主题
Martin Smith

12
@brainstorm:令人惊讶的是,一些虚假陈述在福音中不断重复。聚簇表示,至少从顺序读取的角度来看,将行与索引物理顺序存储在磁盘上是“理想的”,但这与说它将导致它们实际以这种方式存储。
2014年

5
@MartinSmith我已复制并确认您对的测试结果SQL Server 2014。我得到95%的索引碎片的初始插件后。在index rebuild碎片化之后,0%值被排序。我想知道,我们能这么说The only time the data rows in a table are stored in sorted order is when its clustered index fragmentation is 0吗?
gotqn

8
@MartinSmith,主席先生,这是一个答案。我很乐意将其显示在响应列表的顶部,但顺便说一句,“快速而简单”得到了好评。
vaitrafra

5
@Manachi这个问题是在提出原始问题5年后给出的。目的是纠正这些答案的某些误导性方面。OP的(现在已经8岁了)异想天开不是我关心的问题。其他读者可能会喜欢较低级别的视图。
马丁·史密斯

149

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

聚集索引

如果走进公共图书馆,您会发现所有书籍都是按特定顺序排列的(很可能是杜威十进制系统或DDS)。这对应于书籍的“聚集索引”。如果您想要的书的DDS#是005.7565 F736s,则将从找到带有标签001-099或类似内容的书架行开始。(位于堆栈末尾的该结束符与索引中的“中间节点”相对应。)最终,您将向下钻取到标记为的特定书架005.7450 - 005.7600,然后进行扫描,直到找到具有指定DDS#的书,并在到此为止,您已经找到了自己的书。

非丛集索引

但是,如果您没有带着记住的DDS#进入图书馆,那么您将需要第二个索引来帮助您。在过去,您会在图书馆的前部找到一个奇妙的抽屉柜,称为“卡片目录”。其中有成千上万张3x5卡片-每本书一张,按字母顺序(可能按标题)排序。这对应于“非聚集索引”。这些卡目录按层次结构进行组织,以便每个抽屉都用其包含的卡范围(Ka - Kl例如,“中间节点”)进行标记。再次,您将深入研究直到找到您的书,但是在这种情况下,一旦找到它(即“叶节点”),就没有书本了,索引号(DDS#),通过它您可以在聚集索引中找到实际的书。

当然,没有什么能阻止图书管理员影印所有卡并在单独的卡目录中以不同顺序对其进行分类。(通常至少有两个这样的目录:一个按作者名称排序,一个按标题排序。)原则上,您可以根据需要拥有多个“非集群”索引。


2
我也许可以扩展这种类比来描述“包含”列,该可以与非聚簇索引一起使用:可以想象卡目录中的一张卡不仅包括一本书,而且还包含所有已出版书籍的列表。本书的版本,按出版日期进行编号。就像在“包含的列”中一样,此信息仅存储在叶级别(因此减少了馆员必须创建的卡片数量)。
kmote

很好的类比-确实有助于形象化!
丹尼斯,

71

在下面找到聚集索引和非聚集索引的一些特征:

聚集索引

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

非聚集索引

  1. 非聚集索引就像简单索引。它们仅用于快速检索数据。不确定是否具有唯一数据。

34
一个小幅盘整,以点1的聚集索引并没有必然唯一标识一个SQL表中的行。那就是主键的功能
Nigel

4
@Nigel,主键还是唯一索引?
anar khalilov

实际的直接答案,谢谢@Anirudh Sood
Oscar Romero

50

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


47

聚集索引

聚集索引确定表中DATA的物理顺序,因此表仅具有1个聚集索引。

  • 字典 ”不需要任何其他索引,它已经根据单词索引

非聚集索引

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

  • 盯着“ 化学书”,有一个单独的索引指向章节位置,而在“结尾”处,有另一个索引指向普通单词位置

6

聚集索引

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

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

非集群

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

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

参考:https//docs.microsoft.com/zh-cn/sql/relational-databases/indexes/clustered-and-nonclustered-indexes-


4

让我提供一个有关“集群索引”的教科书定义,该定义取自数据库系统:The Complete Book中的 15.6.1 :

我们也可以说聚簇索引,它们是一个或多个属性上的索引,这样,对于该索引的搜索关键字而言,具有固定值的所有元组都将显示在尽可能少的块中。

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

一个关系R(a,b)是对属性进行排序a和存储的顺序,打包成块,肯定是clusterd。索引on a是聚簇索引,因为对于给定的a值a1,具有该值的所有元组a都是连续的。因此,它们似乎打包成块,除了可能包含a-value a1 的第一个和最后一个块 ,如图15.14所示。然而,在为B指数是不太可能聚集,因为与元组固定的b-值会传遍文件,除非值ab非常密切相关。

图15.14

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

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

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

单词“ Cluster”遍布数据库存储端的所有抽象级别(三个抽象级别:元组,块,文件)。称为“ 集群文件 ”的概念,它描述文件(一组块(一个或多个磁盘块)的抽象)是否包含来自一个关系或不同关系的元组。它与文件级别上的聚簇索引概念无关。

然而,一些教材喜欢基于聚类文件定义来定义聚类索引。这两种类型的定义在集群关系级别上都是相同的,无论它们是根据数据磁盘块还是文件来定义集群关系。在本段的链接中,

在以下情况下,文件上属性A的索引是聚簇索引:具有属性值A = a的所有元组顺序(=连续)存储在数据文件中

连续存储元组与说“元组被打包成尽可能少地容纳那些元组的尽可能少的块”相同(一个在谈论文件,另一个在谈论磁盘,差别很小)。这是因为连续存储元组是实现“打包为可能容纳这些元组的尽可能少的块”的方法。


3

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

非聚簇索引:非聚簇索引的 实际数据不能在叶节点上直接找到,而是必须采取额外的步骤来查找,因为它仅具有指向实际数据的行定位符的值。非聚集索引不能作为聚集索引排序。每个表可以有多个非聚集索引,实际上这取决于我们使用的sql server版本。基本上,SQL Server 2005允许249个非聚簇索引,而对于像2008、2016这样的以上版本,每个表允许999个非聚簇索引。


2

聚集索引 -聚集索引定义了数据在表中的物理存储顺序。表数据只能以某种方式排序,因此,每个表只能有一个聚集索引。在SQL Server中,主键约束自动在该特定列上创建聚集索引。

非聚集索引-非聚集索引不会对表内的物理数据进行排序。实际上,非聚集索引存储在一个位置,表数据存储在另一位置。这类似于教科书,其中书的内容位于一个位置,索引位于另一个位置。这样一来,每个表可以有多个非聚集索引。重要的是要在表中提到,数据在表内将按聚集索引进行排序。但是,非聚集索引数据以指定顺序存储在内部。索引包含创建索引的列值和该列值所属的记录的地址。对创建索引的列进行查询时,数据库将首先转到索引并查找表中相应行的地址。然后它将转到该行地址并获取其他列值。由于此附加步骤,非聚集索引比聚集索引慢

聚集索引和非聚集索引之间的差异

  1. 每个表只能有一个聚集索引。但是,您可以在单个表上创建多个非聚集索引。
  2. 聚集索引仅对表进行排序。因此,它们不会消耗额外的存储空间。非聚集索引存储在与实际表不同的位置,从而占用更多存储空间。
  3. 聚簇索引比非聚簇索引要快,因为它们不涉及任何额外的查找步骤。

欲了解更多信息,请参阅文章。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.