我对DB的接触有限,只是作为应用程序程序员使用过DB。我想知道关于聚集和非聚集索引。 我在谷歌上搜索了一下,我发现:

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中发现的是聚集索引和非聚集索引之间的区别是什么?

有人能用通俗易懂的语言解释一下吗?


当前回答

聚集索引

聚集索引基本上是一个树状组织的表。与将记录存储在未排序的Heap表空间中不同,聚集索引实际上是具有叶子节点(按群集键列值排序)的B+树索引,存储实际的表记录,如下图所示。

在SQL Server和MySQL中,Clustered Index是默认的表结构。即使表没有主键,MySQL也会添加一个隐藏的集群索引,而SQL Server总是在表有主键列时构建一个集群索引。否则,SQL Server将存储为堆表。

聚集索引可以加速按聚集索引键过滤记录的查询,就像通常的CRUD语句一样。由于记录位于叶节点中,因此在根据记录的Primary Key值定位记录时,不需要额外查找额外的列值。

例如,在SQL Server上执行如下SQL查询:

SELECT PostId, Title
FROM Post
WHERE PostId = ? 

您可以看到,执行计划使用群集索引查找操作来定位包含Post记录的叶子节点,并且扫描群集索引节点只需要两个逻辑读取:

|StmtText                                                                             |
|-------------------------------------------------------------------------------------|
|SELECT PostId, Title FROM Post WHERE PostId = @P0                                    |
|  |--Clustered Index Seek(OBJECT:([high_performance_sql].[dbo].[Post].[PK_Post_Id]), |
|     SEEK:([high_performance_sql].[dbo].[Post].[PostID]=[@P0]) ORDERED FORWARD)      | 

Table 'Post'. Scan count 0, logical reads 2, physical reads 0

非聚簇索引

由于聚集索引通常是使用主键列值构建的,如果您想加快使用其他列的查询速度,那么必须添加次要非聚集索引。

二级索引将在它的叶节点中存储主键值,如下图所示:

因此,如果我们在Post表的Title列上创建一个Secondary Index:

CREATE INDEX IDX_Post_Title on Post (Title)

然后执行下面的SQL查询:

SELECT PostId, Title
FROM Post
WHERE Title = ? 

我们可以看到,索引查找操作用于在IDX_Post_Title索引中定位叶子节点,它可以提供我们感兴趣的SQL查询投影:

|StmtText                                                                      |
|------------------------------------------------------------------------------|
|SELECT PostId, Title FROM Post WHERE Title = @P0                              |
|  |--Index Seek(OBJECT:([high_performance_sql].[dbo].[Post].[IDX_Post_Title]),|
|     SEEK:([high_performance_sql].[dbo].[Post].[Title]=[@P0]) ORDERED FORWARD)|

Table 'Post'. Scan count 1, logical reads 2, physical reads 0

由于相关的PostId主键列值存储在IDX_Post_Title叶节点中,因此此查询不需要额外查找来定位聚集索引中的Post行。

其他回答

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

聚集索引

聚类索引决定了表中DATA的物理顺序。因此,一个表只有一个聚集索引(主键/组合键)。

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

非聚集索引

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

“生物书”在开头有一个单独的索引指向章节的位置,在“结尾”有另一个索引指向常用单词的位置

让我提供一个关于“聚类索引”的教科书定义,摘自Database Systems: The Complete Book中的15.6.1:

我们也可以称之为聚类索引,它是一个或多个属性上的索引,这样所有具有该索引的搜索键的固定值的元组都出现在能够容纳它们的大致尽可能少的块上。

为了理解定义,让我们看一下教科书提供的例子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.

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

A related concept is clustered relation. A relation is "clustered" if its tuples are packed into roughly as few blocks as can possibly hold those tuples. In other words, from a disk block perspective, if it contains tuples from different relations, then those relations cannot be clustered (i.e., there is a more packed way to store such relation by swapping the tuples of that relation from other disk blocks with the tuples the doesn't belong to the relation in the current disk block). Clearly, R(a,b) in example above is clustered.

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

“集群”作为一个词在数据库存储端的所有抽象级别(三个抽象级别:元组、块、文件)上被大量发送。一个叫做“集群文件”的概念,它描述了一个文件(一组块(一个或多个磁盘块)的抽象)是否包含来自一个关系或不同关系的元组。它与集群索引概念无关,因为它是在文件级别上。

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

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

连续存储元组就相当于说“元组被打包到尽可能少的块中,以容纳这些元组”(一个是文件,另一个是磁盘)。这是因为连续存储元组是实现“将这些元组打包到尽可能少的块中”的方法。

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

Non Clustered Index: Actual data of non clustered index is not directly found at leaf node, instead it has to take an additional step to find because it has only values of row locators pointing towards actual data. Non clustered Index can't be sorted as clustered index. There can be multiple non clustered indexes per table, actually it depends on the sql server version we are using. Basically Sql server 2005 allows 249 Non Clustered Indexes and for above versions like 2008, 2016 it allows 999 Non Clustered Indexes per table.

聚集索引意味着您告诉数据库在磁盘上存储实际上彼此接近的接近值。这样做的好处是可以快速扫描/检索某些聚集索引值范围内的记录。

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

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

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

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

附注:CustomerID上的索引显然不是唯一的,因此您要么需要添加第二个字段来“唯一”索引,要么让数据库为您处理,但这是另一回事。

Regarding multiple indexes. You can have only one clustered index per table because this defines how the data is physically arranged. If you wish an analogy, imagine a big room with many tables in it. You can either put these tables to form several rows or pull them all together to form a big conference table, but not both ways at the same time. A table can have other indexes, they will then point to the entries in the clustered index which in its turn will finally say where to find the actual data.