11

通常聚集索引是通过设置主键在 SQL Server Management Studio 中创建的,但是我最近关于 PK <-> 聚集索引的问题(Microsoft SQL Server 2008 的主键含义)表明没有必要设置 PK 和聚集索引相等。

那么我们应该如何选择聚集索引呢?让我们举个例子:

create table Customers (ID int, ...)
create table Orders (ID int, CustomerID int)

我们通常会在两个 ID 列上创建 PK/CI,但我考虑为 CustomerID 中的订单创建它。那是最好的选择吗?

4

3 回答 3

13

根据索引女王金伯利·特里普(Kimberly Tripp)的说法,她在聚集索引中寻找的主要是:

  • 独特
  • 狭窄的
  • 静止的

如果您还可以保证:

  • 不断增加的模式

那么您就非常接近拥有理想的集群密钥了!

在这里查看她的整篇文,以及关于集群对表操作的关键影响的另一篇非常有趣的博文:集群索引辩论继续

像 INT(尤其是 INT IDENTITY)或可能是 INT 和 DATETIME 之类的任何东西都是理想的候选人。由于其他原因,GUID 根本不是很好的候选者——所以你可能有一个 GUID 作为你的 PK,但不要将你的表聚集在它上面——它会被碎片化得面目全非,性能也会受到影响。

于 2010-02-15T16:47:27.073 回答
6

索引的最佳候选者CLUSTERED是您最常用于引用记录的键。

通常,这是 a PRIMARY KEY,因为它用于搜索和/或FOREIGN KEY关系。

在您的情况下,Orders.ID很可能会参与搜索和引用,因此它是作为聚类表达式的最佳候选者。

如果在CLUSTERED上创建索引Orders.CustomerID,会发生以下情况:

  1. CustomerID不是唯一的。为了确保唯一性,每条记录都会添加一个特殊的隐藏32-bit列。uniquifier

  2. 表中的记录将根据这对列进行存储(CustomerID, uniquifier)

  3. Order.ID将创建一个二级索引,(CustomerID, uniquifier)作为记录指针。

  4. 像这样的查询:

    SELECT  *
    FROM    Orders
    WHERE   ID = 1234567
    

    将不得不执行外部操作 a Clustered Seek,因为并非所有列都存储在 上的索引中ID。要检索所有列,记录应首先位于聚簇表中。

这个额外的操作需要IndexDepth尽可能多的页面读取Clustered Seek,即表中IndexDepth记录O(log(n))的总数。

于 2010-02-15T16:36:31.213 回答
1

如果您担心聚类,通常是为了帮助改进数据检索。在您的示例中,您可能希望一次获得给定客户的所有记录。在 customerID 上进行聚类将使这些行保持在同一个物理页面上,而不是分散在文件中的多个页面中。

ROT:在您要显示的集合上进行聚类。采购订单中的行项目就是典型的例子。

于 2010-02-15T16:36:05.137 回答