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

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


当前回答

下面是聚类索引和非聚类索引的一些特征:

聚集索引

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

非聚簇索引

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

其他回答

下面是聚类索引和非聚类索引的一些特征:

聚集索引

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

非聚簇索引

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

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

Non-Clustered Index - A non-clustered index doesn’t sort the physical data inside the table. In fact, a non-clustered index is stored at one place and table data is stored in another place. This is similar to a textbook where the book content is located in one place and the index is located in another. This allows for more than one non-clustered index per table.It is important to mention here that inside the table the data will be sorted by a clustered index. However, inside the non-clustered index data is stored in the specified order. The index contains column values on which the index is created and the address of the record that the column value belongs to.When a query is issued against a column on which the index is created, the database will first go to the index and look for the address of the corresponding row in the table. It will then go to that row address and fetch other column values. It is due to this additional step that non-clustered indexes are slower than clustered indexes

聚类索引和非聚类索引的区别

每个表只能有一个聚集索引。但是,你可以 在一个表上创建多个非聚集索引。 聚集索引只对表进行排序。因此,他们不消费 额外的存储。非聚集索引存储在单独的位置 从实际表中占用更多的存储空间。 聚集索引比非聚集索引快,因为它们 不要涉及任何额外的查找步骤。

有关更多信息,请参阅本文。

让我提供一个关于“聚类索引”的教科书定义,摘自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的所有元组按顺序(=连续)存储在数据文件中

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

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

(图片来源)

聚类索引与非聚类索引之间的关键区别在于,聚类索引的叶级是表。这有两个含义。

聚集索引叶页上的行总是包含表中每个(非稀疏)列的内容(值或指向实际值的指针)。 聚集索引是表的主副本。

非聚集索引也可以通过使用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在线书籍引起了很多混乱

在我看来,这样说更好。

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

The book's online quote is not incorrect but you should be clear that the "sorting" of both non clustered and clustered indices is logical, not physical. If you read the pages at leaf level by following the linked list and read the rows on the page in slot array order then you will read the index rows in sorted order but physically the pages may not be sorted. The commonly held belief that with a clustered index the rows are always stored physically on the disk in the same order as the index key is false.

这将是一个荒谬的实现。例如,如果一行被插入到一个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总是确保这两种类型的索引的键列是唯一的。但是,对于没有声明为唯一的索引,两种索引类型的强制机制是不同的。

聚集索引将为键值与现有行的重复的任何行添加唯一符。这只是一个升序整数。

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

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

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

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

聚集索引

If you walk into a public library, you will find that the books are all arranged in a particular order (most likely the Dewey Decimal System, or DDS). This corresponds to the "clustered index" of the books. If the DDS# for the book you want was 005.7565 F736s, you would start by locating the row of bookshelves that is labeled 001-099 or something like that. (This endcap sign at the end of the stack corresponds to an "intermediate node" in the index.) Eventually you would drill down to the specific shelf labelled 005.7450 - 005.7600, then you would scan until you found the book with the specified DDS#, and at that point you have found your book.

非聚簇索引

But if you didn't come into the library with the DDS# of your book memorized, then you would need a second index to assist you. In the olden days you would find at the front of the library a wonderful bureau of drawers known as the "Card Catalog". In it were thousands of 3x5 cards -- one for each book, sorted in alphabetical order (by title, perhaps). This corresponds to the "non-clustered index". These card catalogs were organized in a hierarchical structure, so that each drawer would be labeled with the range of cards it contained (Ka - Kl, for example; i.e., the "intermediate node"). Once again, you would drill in until you found your book, but in this case, once you have found it (i.e, the "leaf node"), you don't have the book itself, but just a card with an index number (the DDS#) with which you could find the actual book in the clustered index.

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