【问题标题】:Should every User Table have a Clustered Index?每个用户表都应该有一个聚集索引吗?
【发布时间】:2012-08-01 00:49:33
【问题描述】:

最近我在数据库中发现了几个没有定义聚集索引的表。 但是定义了非聚集索引,所以它们在 HEAP 上。

经过分析,我发现 select 语句对非聚集索引中定义的列使用了过滤器。

在这些表上没有聚集索引会影响性能吗?

【问题讨论】:

  • 是的,否则你有一个堆是坏的。堆变得碎片化,所以这不好。

标签: sql-server sql-server-2008 indexing sql-server-2008-r2 sqlperformance


【解决方案1】:

我不会说“每个表都应该有一个聚集索引”,我会说“仔细查看每个表以及它们是如何被访问的,并尝试在其上定义一个聚集索引如果有意义的话”。这是一个优点,就像小丑一样,每张桌子只有一个小丑,但您不必必须使用它。其他数据库系统没有这个,至少在这种形式下,顺便说一句。

在不了解您在做什么的情况下将聚集索引放在任何地方也会影响您的性能(通常,INSERT 性能,因为聚集索引意味着在磁盘上进行物理重新排序,或者至少这是理解它的好方法) ,例如我们看到越来越多的 GUID 主键。

所以,请阅读 Tim Lehner 的例外和原因。

【讨论】:

    【解决方案2】:

    很难比 SQL Server MVP Brad McGehee 更简洁地说明这一点:

    As a rule of thumb, every table should have a clustered index. 通常,但并非总是如此,聚集索引应该位于单调增加的列上——例如标识列,或值增加的其他列——并且是唯一的.在许多情况下,主键是聚集索引的理想列。

    BOL 表达了这种观点:

    除了少数例外,每个表都应该有一个聚集索引。

    这样做的原因有很多,主要是基于以下事实:聚集索引对存储中的数据进行物理排序

    • 如果您的聚集索引在单个列上单调增加,则插入会在您的存储设备上按顺序发生,并且不会发生页面拆分。

    • 当索引值唯一时,聚集索引对于查找特定行非常有效,例如基于主键选择行的常见模式。

    • 聚集索引often 允许对经常搜索值范围(between> 等)的列进行高效查询。

    • 在数据通常按特定列或多列排序的情况下,聚类可以加快查询速度。

    • 可以根据需要重建或重组聚集索引以控制表碎片。

    • 这些好处甚至可以是applied to views

    您可能不想在以下位置创建聚集索引:

    • 具有频繁数据更改的列,因为 SQL Server 必须对存储中的数据进行物理重新排序。

    • 已经被其他索引覆盖的列。

    • 宽键,因为聚集索引也用于非聚集索引查找。

    • GUID 列,它们大于标识,并且还有效地随机值(不太可能被排序),尽管newsequentialid() 可用于帮助减少插入期间的物理重新排序。

    • 使用heap(没有聚集索引的表)的一个罕见原因是,如果始终通过非聚集索引访问数据并且已知 RID(SQL Server 内部行标识符)小于聚集索引索引键。

    由于这些和其他考虑因素,例如您的特定应用程序工作负载,您应该仔细选择聚集索引,以便为您的查询获得最大收益。

    另请注意,当您在 SQL Server 中的表上创建主键时,默认情况下会创建一个唯一的聚集索引(如果还没有)。这意味着,如果您发现一个表没有聚集索引,但确实有一个主键(所有表都应该如此),那么开发人员之前已决定以这种方式创建它。您可能希望有一个令人信服的理由来改变这一点(正如我们所见,其中有很多)。 添加、更改或删除聚集索引需要重写整个表和任何非聚集索引,因此在大型表上这可能需要一些时间。

    【讨论】:

    • 您能解释一下第三个项目符号聚集索引允许对经常搜索值范围(介于、> 等)的列进行高效查询。??跨度>
    • 聚集索引以这种方式工作得很好,因为下一个更高或更低键控的行在存储中保证在物理上彼此相邻。因此,一旦找到第一个值,就不需要搜索剩余的行;你已经找到了。
    • @TimLehner - 非常好的帖子...为此 +1...我今天学到了一些东西!
    • 不能保证它们在存储中物理上相邻。它们只保证在逻辑上相邻。这就是您需要重新组织或重建索引的原因。
    • 有趣的文章在这里推堆:use-the-index-luke.com/blog/2014-01/…
    【解决方案3】:

    是的,每个表都应该有一个聚集索引。聚集索引设置表中数据的物理顺序。您可以将其与在商店中按乐队名称或黄页按姓氏排序的音乐排序进行比较。由于这涉及物理顺序,因此您只能拥有一个,它可以由许多列组成,但您只能拥有一个。

    最好将聚集索引放在经常搜索一系列值的列上。示例是日期范围。当索引值唯一时,聚集索引对于查找特定行也很有效。 如果没有定义聚簇索引,Microsoft SQL 会自动将聚簇索引放在 PRIMARY KEY 约束上。

    聚集索引不是一个好的选择:

    经常变化的列

    • 这会导致整行移动(因为 SQL Server 必须保持 按物理顺序排列的一行的数据值)。这是一个重要的 考虑在大容量事务处理系统中 数据往往不稳定。

    宽键

    • 聚集索引中的键值被所有人使用 非聚集索引作为查找键,因此存储在每个 非聚集索引叶条目。

    【讨论】:

    • 你能用一个例子来解释一下吗最好将聚集索引放在经常搜索一系列值的列上。例如日期范围,此时聚集索引中的键值被所有非聚集索引用作查找键,因此存储在每个非聚集索引叶条目中。
    • 另一个要考虑的因素是,如果你不断更新、插入和删除数据,每个索引,包括聚集的索引(如果有的话),都必须重新排序,等等。堆表(没有聚集索引)对于这些操作通常是最快的。
    【解决方案4】:

    性能是个棘手的问题。确保您针对正确的事情进行优化。

    免费建议总是物有所值,而且没有什么可以替代实际实验。

    索引的目的是找到匹配的行并在找到时帮助检索数据。

    基于搜索条件的非聚集索引将有助于查找行,但需要进行额外操作才能获取行数据。

    如果没有聚集索引,SQL 使用内部 rowId 来指向数据的位置。

    但是,如果表上有聚集索引,则该 rowId 将替换为聚集索引中的数据值。

    因此不需要读取行数据的步骤,并且会被索引中的值覆盖。

    即使聚集索引的选择性不是很好,但如果这些键经常是请求的大部分或全部结果 - 将它们作为非聚集索引的叶子可能会有所帮助。

    【讨论】:

      【解决方案5】:

      当列包含大量不同的值时,考虑使用clustered index,以避免 SQL Server 需要添加“唯一符”来重复键值

      缺点:如果只更改聚簇索引中的字段,更新记录的时间会更长。

      避免集群索引构造,其中存在许多并发插入将发生在几乎相同的集群索引值上的风险

      如果聚集索引没有正确构建,或者它不包括将数据返回给调用应用程序所需的所有列,则对非聚集索引的搜索会显得较慢。如果非聚集索引不包含所有需要的数据,则 SQL Server 将转到聚集索引以获取丢失的数据(通过查找),这将使查询运行速度变慢,因为查找完成行按行。

      【讨论】:

        【解决方案6】:

        是的,您应该在表上拥有聚集索引。这样所有非聚集索引的性能都会更好。

        【讨论】:

        猜你喜欢
        • 2010-10-24
        • 1970-01-01
        • 1970-01-01
        • 2019-04-09
        • 2011-02-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多