【问题标题】:Does clustered index on foreign key column increase join performance vs non-clustered?外键列上的聚集索引与非聚集索引相比是否会提高连接性能?
【发布时间】:2011-01-26 14:33:04
【问题描述】:

在许多地方,建议在使用 BETWEEN 语句选择行范围时更好地利用聚集索引。当我以使用此聚集索引的方式选择通过外键字段连接时,我想,集群化也应该有所帮助,因为正在选择行的范围,即使它们都具有相同的聚集键值并且未使用 BETWEEN。

考虑到我只关心那个带有 join 的 select 而不是其他的,我的猜测是不是错了?

【问题讨论】:

    标签: sql performance join foreign-keys clustered-index


    【解决方案1】:

    如果您在集群中按顺序选择数据,通常会获得性能提升。此外,这完全取决于表(数据)的大小和 between 语句中的条件。

    【讨论】:

      【解决方案2】:

      FK 列上的索引将有助于 JOIN,因为索引本身是有序的:聚集只是意味着磁盘(叶)上的数据是有序的,而不是 B 树。

      如果将其更改为覆盖索引,则聚集与非聚集无关。重要的是要有一个有用的索引。

      【讨论】:

      • @gbn:谢谢你最准确的回答,我的理解是否正确,你不同意 marc_s 和 mjv,你说不相关,他们说相关?
      • 我回答了关于 Kk 索引的问题:marc_s 回答了一般关于聚集索引的问题(并且对我的回答发表了过于积极的评论)。 mjv 好像跟我说的一样。
      【解决方案3】:

      这取决于数据库的实现。

      对于 SQL Server,聚集索引是一种数据结构,其中数据存储为页面,并且存在 B 树并存储为单独的数据结构。您获得快速性能的原因是您可以快速到达链的开始,并且范围是一个易于遵循的链表。

      非聚集索引是一种数据结构,其中包含指向实际记录的指针以及不同的关注点。

      请参阅有关Clustered Index Structures 的文档。

      索引对外键关系没有帮助,但由于“覆盖”索引的概念,它会有所帮助。如果您的 WHERE 子句包含基于索引的约束。它将能够更快地生成返回的数据集。这就是性能的来源。

      【讨论】:

      • 所以我的问题是,“链的开始快速且范围是一个简单的链表”是否可以用于选择并通过 FK 字段连接?
      • 不是通过连接,而是通过 WHERE 子句。如果 FK 和被覆盖的索引以及 WHERE 约束是同一列,那么是的。
      • 所以如果我只在 join 内部使用 FK 列,而不在 WHERE 内部使用,那么集群与非集群无关?
      • 大部分...因为如果您在 ON X.c1 = Y.c2 AND (X.c1 >= 30 AND X.c1
      • 如果我只使用 ON X.c1 = Y.c2 会怎样?
      【解决方案4】:

      绝对讨论这类问题不是很有用。

      这总是一个个案的情况!

      基本上,通过聚集索引进行访问可以节省一个间接访问,句号。

      假设在 JOIN 中使用的键是聚集索引的键,在单次读取中[无论是从索引查找还是从扫描或部分扫描,都没有关系],您将获得整行(记录) .

      聚集索引的一个问题是每个表只能获得一个。因此,您需要明智地使用它。实际上,在某些情况下,由于 INSERT 开销和碎片(取决于键和新键的顺序等),根本不使用任何聚簇索引更为明智。

      有时,使用covering index 可以获得与聚集索引相同的好处,即具有所需键序列的索引,后跟我们感兴趣的列值。就像聚集索引一样,覆盖index 不需要对基础表的间接寻址。实际上,覆盖索引可能比聚集索引更有效,因为它更小。
      然而,就像聚集索引一样,除了存储开销之外,在 INSERT(以及 DELETE 或 UPDATE)查询期间,任何额外的索引都会带来性能成本

      而且,是的,如其他答案所示,用于聚集索引的键的“外键性”对索引的性能绝对没有影响。 FK 是旨在简化数据库完整性维护的约束,但底层字段(列)与表中的任何其他字段一样。

      要对索引结构做出明智的决定,需要

      • 了解各种索引类型(和堆)的工作方式
        (顺便说一句,这在 SQL 实现之间有所不同)
      • 对现有数据库的统计概况有一个良好的印象:
        哪些是大表,哪些是关系,关系的平均/最大基数是多少,数据库的典型增长率是多少等。
      • 深入了解数据库的使用/查询方式

      只有到那时,人们才能对拥有给定聚集索引的兴趣 [或缺乏兴趣] 做出有根据的猜测。

      【讨论】:

      • 行为改变。我有一个查询在 SQL Server 2000 中经过优化并以一种方式工作,然后在 SQL Server 2005 中失败并以不同方式工作。绝对不是这种情况,因为它可能是特定于供应商的。
      • @alpav:假设您的查询有效地访问了 JOINed 表中的至少一个字段(很可能是这种情况),简短的回答是“是!,聚集索引用于您提到的查询提高了性能[与仅 PK 上的普通非聚集索引相比]”。长答案是“还有许多其他因素;查询可能会从其他来源获得更大的性能提升;这不应该是对这个甚至聚集索引的认可;......”所以,是的,你的情况足够具体...
      • ...保证技术上的准确答案,但这可能无法解决全局问题。另外:这不是[完全]对您的问题的投诉,而是表明在一个简短的问题中公开足够的上下文并不容易,因此在此论坛上关于 SQL 性能的 Q/A 的半相关性.
      • @mjv:是的,你当然做到了——非常清楚和完美。对不起,mea cupla - 我没听懂那部分......
      • @marc_s: NP,不需要过失 ;-) 我经常在解释事情方面做得很糟糕(见我的头像照片)。我还开始删除对这个特定问题的评论以保持整洁(因为所有内容都包含在答案中)。
      【解决方案5】:

      我会问其他问题:将聚集索引放在外键列上只是为了加快单个 JOIN 是否明智?它可能会有所帮助,但是……要付出代价!

      对于每个操作,聚集索引使表更快。是的!确实如此。有关背景信息,请参阅 Kim Tripp 的优秀 The Clustered Index Debate continues。她还提到了她对聚集索引的主要标准:

      • 静态(永不改变)
      • 独一无二的
      • 如果可能的话:不断增加

      INT IDENTITY 完美地实现了这一点 - GUID 没有。有关详细背景信息,请参阅 GUID's as Primary Key

      为什么要缩小?因为在同一张表的每一个非聚集索引的每一个索引页上都添加了聚集键(为了能够实际查找到数据行, 如果需要的话)。您不想在集群键中包含 VARCHAR(200)....

      为什么是唯一的?? 见上文 - 群集键是 SQL Server 用于唯一查找数据行的项和机制。它必须是独一无二的。如果您选择一个非唯一的集群键,SQL Server 本身会为您的键添加一个 4 字节的唯一符。小心那个!

      所以这些是我的标准 - 将您的集群键放在一个狭窄、稳定、独特、希望不断增加的列上。如果您的外键列与那些匹配 - 完美!

      但是,在任何情况下,我都不会将我的集群键放在宽外键甚至复合外键上。请记住:聚集键的值被添加到该表上的每个非聚集索引条目中!如果您有 10 个非聚集索引,表中有 100'000 行 - 那就是一百万个条目。无论是 4 字节整数还是 200 字节 VARCHAR - HUGE,都会产生巨大的差异。不仅在磁盘上 - 在服务器内存中也是如此。非常非常仔细地考虑如何制作您的聚集索引!

      SQL Server 可能需要添加一个唯一性 - 使事情变得更糟。如果值会发生变化,SQL Server 将不得不做大量的簿记和更新。

      简而言之:

      • 在外键上放置索引绝对是个好主意 - 一直这样做!
      • 我会非常小心地将它设为聚集索引。首先,你只得到一个聚集索引,那么你要选择哪个 FK 关系呢?并且不要将聚类键放在一个宽且不断变化的列上

      【讨论】:

      • @marc_s:我的理解是否正确,您不同意 gbn,您说集群化与连接相关,而 gbn 说不是?
      • @alpav:我不认为 gbn 这么说 :-) 但他非常正确地指出:最重要的一点是在外键列上有一个索引。是否集群是次要的。
      • 我知道这一点以及所有其他答案中提到的大部分内容,但我仍然没有得到关于我不知道的明确答案 - 如果没有 BETWEEN,集群化会提高连接速度,>= ,
      • @alpav:如果您希望我的直觉是“是或否” - 但仅此而已,没有事实支持 - 我不得不说“不,让这样的索引成为聚集索引不会给您带来任何好处”。但再说一遍:只是一种简单的直觉,没有数据支持。
      • @MDeSchaepmeester:即使它们是伪顺序的 - 它们仍然是int四倍大,因此对于聚集索引来说不是最优的....
      猜你喜欢
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      • 2011-07-02
      • 2011-03-24
      • 2011-10-12
      • 2012-04-30
      • 2012-05-20
      • 2020-08-04
      相关资源
      最近更新 更多