聚簇和非聚簇索引究竟意味着什么?

我对数据库的暴露程度有限,只使用数据库作为应用程序员。 我想知道有关聚簇和非聚簇索引。 我GOOGLE了,我发现是:

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

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

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

对于聚集索引,行按照与索引相同的顺序物理地存储在磁盘上。 因此,只能有一个聚集索引。

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

如果要取回所有列,通常从聚簇索引读取速度更快。 你不必先到索引,然后到桌面。

如果需要重新排列数据,写入到具有聚簇索引的表格可能会变慢。

聚集索引意味着您正在告诉数据库在磁盘上存储实际上彼此接近的值。 这有利于快速扫描/检索落入某些聚集索引值范围内的记录。

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

Customer ---------- ID Name Address Order ---------- ID CustomerID Price 

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

PS CustomerID上的索引显然不是唯一的,所以您需要添加第二个字段来“分离”索引或让数据库为您处理,但这是另一回事。

关于多个指标。 每个表只能有一个聚簇索引,因为这定义了数据的物理排列方式。 如果你想比喻一下,想象一个有很多桌子的大房间。 你可以把这些表格形成几行或者把它们全部拉在一起形成一个大的会议桌,但是不能同时进行。 一个表可以有其他的索引,然后它们将指向聚集索引中的条目,这些条目最终将说明在哪里找到实际的数据。

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

在这里输入图像描述

( 图片来源 )

聚簇索引和非聚簇索引的关键区别在于,聚簇索引的叶子层次表格。 这有两个含义。

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

非聚集索引也可以通过使用INCLUDE子句(自SQL Server 2005以来)明确包含所有非键列,但是它们是次要表示,并且总是有另一个数据副本(表本身)。

 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在线书籍引用引起了许多混淆(因为这是坦率的误导)。 在我看来,这会好得多。

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

在这里输入图像描述

CI行和表行按照同样的方式排列是相当正确的(与上图中的小猫的排列方式与婴儿猫的排列方式相同),但是普遍持有的信念对于聚集索引,行总是以与索引为假相同的顺序物理地存储在磁盘上。

这将是一个荒谬的实施。 例如,如果将一行插入到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 Column Stores状态

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

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

聚集索引

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

非聚集索引

  1. 非聚集索引就像简单的索引。 它们仅用于快速检索数据。 不确定有独特的数据。

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

集群索引

如果你走进一个公共图书馆,你会发现这些书都是按照特定的顺序排列的(最有可能是杜威十进制(DDS))。 这对应于书籍的“聚集索引” 。 如果你想要的书的DDS#是005.7565 F736s ,你可以从标有001-099的那一排书架开始。 (堆栈末尾的尾部标记对应于索引中的“中间节点”。)最终,您将深入到标有005.7450 - 005.7600的特定货架,然后扫描,直到找到具有指定DDS# ,那时候你已经找到了你的书。

非集群指数

但是如果你没有带着你书中的DDS#进入图书馆,那么你需要第二个索引来帮助你。 在过去的一段时间里,您可以在图书馆的前面找到一个称为“卡片目录”的出色的抽屉柜。 其中有数千张3×5的卡片 – 每本书一本,按字母顺序排列(可能是标题)。 这对应于“非聚集索引” 。 这些卡片目录是按照层次结构组织的,所以每个抽屉都会标上它所包含的卡片的范围(例如Ka - Kl ,即“中间节点”)。 再一次,你会钻入,直到你找到你的书,但在这种情况下,一旦你找到了它(即“叶节点”),你没有书本身,而只是一张卡片索引号(DDS#),你可以在聚集索引中找到实际的书。

当然,没有什么能够阻止图书管理员复印所有的卡片,并以不同的顺序将它们分类在单独的卡片目录中。 (通常至少有两个这样的目录:一个按作者姓名排序,另一个按标题排序。)原则上,你可以拥有任意数量的“非群集”索引。

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

聚集索引

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

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

非聚集

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

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

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