【问题标题】:Clustered vs Non-Clustered集群与非集群
【发布时间】:2011-11-28 04:11:54
【问题描述】:

我对 SQL (Server 2008) 的低级知识有限,现在正受到我们的 DBA 的挑战。让我解释一下(我已经提到了明显的陈述,希望我是对的,但是如果您发现有问题,请告诉我)场景:

我们有一张桌子,上面放着人们的“法庭命令”。当我创建表(名称:CourtOrder)时,我创建它的方式如下:

CREATE TABLE dbo.CourtOrder
(
  CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
  PersonId INT NOT NULL,
  + around 20 other fields of different types.
)

然后我将非聚集索引应用于主键(为了提高效率)。我的理由是它是一个唯一字段(主键),应该被索引,主要是为了选择目的,就像我们经常Select from table where primary key = ...

然后我在 PersonId 上应用了一个 CLUSTERED 索引。原因是对特定人的订单进行物理分组,因为绝大多数工作都是为一个人获得订单。所以,select from mytable where personId = ...

我现在已经被吸引了。有人告诉我,我们应该将聚集索引放在主键上,将普通索引放在 personId 上。这对我来说似乎很奇怪。首先,为什么要将聚集索引放在唯一列上?它是什么聚类?这肯定是对聚集索引的浪费吗?我曾相信正常索引将用于唯一列。此外,对索引进行聚类意味着我们不能对不同的列进行聚类(每个表一个,对吗?)。

我被告知我犯了一个错误的原因是他们认为在 PersonId 上放置一个聚集索引会使插入变慢。对于 5% 的选择速度增益,我们的插入和更新速度将降低 95%。这正确有效吗?

他们说,因为我们对 personId 进行了聚类,所以当我们插入或更改 PersonId 时,SQL Server 必须重新排列数据。

然后我问,如果 SQL 这么慢,为什么会有 CLUSTERED INDEX 的概念?有他们说的那么慢吗?我应该如何设置索引以实现最佳性能?我原以为 SELECT 比 INSERT 使用得更多……但他们说我们在 INSERTS 上遇到了锁定问题……

希望有人可以帮助我。

【问题讨论】:

标签: sql performance sql-server-2008 indexing


【解决方案1】:

聚集索引与非聚集索引的区别在于聚集索引确定数据库中行的物理顺序。换句话说,将聚集索引应用于PersonId 意味着行将在表中按PersonId 进行物理排序,从而允许对其进行索引搜索直接到行(而不是非聚集索引,这将引导您到该行的位置,添加一个额外的步骤)。

也就是说,主键不是聚集索引是不寻常的,但并非闻所未闻。您的方案的问题实际上与您的假设相反:您希望聚集索引中的 unique 值,而不是重复值。因为聚集索引确定行的物理顺序,如果索引位于非唯一列上,则服务器必须为具有重复键值的行添加背景值(在您的情况下,任何具有相同键值的行) PersonId) 以便组合值(键 + 背景值)是唯一的。

我唯一建议的是不要使用代理键(您的CourtOrderId)列作为主键,而是使用PersonId 的复合主键和其他一些唯一的- 识别列或列集。但是,如果这不可能(或不切实际),则将聚集索引放在CourtOrderId 上。

【讨论】:

  • 谢谢亚当。那么,聚集索引什么时候有用呢?我认为聚集索引的好处是对数据进行分组,例如,当大多数查询都在 PersonID 上时……所以数据会被分组。
  • 没有PersonId物理排序。按PersonId进行逻辑排序,任何逻辑顺序和物理顺序的差异,都是逻辑碎片的程度。
  • @cdotlister 索引的好处是对数据进行排序,而不是对其进行分组(这意味着索引中存在重复数据)。虽然这种区别似乎是语义上的,但在聚集索引的情况下却不是。如果可能,聚集索引应该在唯一标识行的东西上,并且(理想情况下)也是最常查询的列或列集。这就是为什么它通常在主键上。
  • @Cyber​​SluethOmega:我不知道;你的问题没有包含足够的信息让我做出决定。我是否希望在一组列上创建一个聚集索引,在这些列中,行会经常添加或删除除了在表的末尾?不。但我不太确定你为什么要问这个问题或为什么要投反对票。
  • @Cyber​​SluethOmega:互联网会让 cmets 听起来像是防御性的或冷漠的,但并非如此。你声称我说我不知道​​在什么情况下使聚集索引成为主键以外的东西,而实际上我没有说过这样的话。事实上,我所说的是“这不寻常......,但并非闻所未闻”,这意味着我确实知道这样做的情况。跨度>
【解决方案2】:

我绝不是 SQL 专家...所以请将此视为开发人员的观点,而不是 DBA 的观点..

在不按顺序的聚集(物理排序)索引上插入会导致插入/更新的额外工作。此外,如果您有许多插入同时发生并且它们都发生在同一个位置,那么您最终会出现争用。您的具体表现因您的数据和访问方式而异。一般的经验法则是在表中最独特的窄值(通常是 PK)上构建聚集索引

我假设您的 PersonId 不会改变,因此更新不会在这里发挥作用。但是考虑一下 PersonId 为的几行的快照 1 2 3 3 4 5 6 7 8 8

现在为 PersonId 为 3 插入 20 个新行。首先,由于这不是唯一键,服务器会在您的值中添加一些额外的字节(在幕后)以使其唯一(这也增加了额外的空间),然后这些将居住的位置必须改变。将其与插入在末尾发生的自动递增 PK 进行比较。非技术性的解释可能会归结为:如果它在表格末尾自然地取得更高的值,而不是在插入物品时在该位置重新加工现有物品的位置,那么“洗牌”工作要做的就更少了。

现在,如果您在使用 Inserts 时遇到问题,那么您可能会同时插入一堆相同(或相似)的 PersonId 值,这会导致在整个表格的各个位置进行这项额外工作,并且碎片会杀死您。在您的情况下切换到集群的 PK 的缺点是,如果您今天在 PersonIds 上的插入问题在整个表中分布的值不同,如果您将集群索引切换到 PK 并且所有插入现在都发生在一个位置,那么由于争用集中度增加,您的问题实际上可能会变得更糟。 (另一方面,如果您今天的插入不是遍布各处,而是通常都集中在相似的区域,那么您的问题可能会通过将聚集索引从 PersonId 切换到您的 PK 来缓解,因为您将最小化碎片化。)

应根据您的独特情况分析您的性能问题,并将这些类型的答案仅作为一般指导。最好的办法是依靠能够准确验证问题所在的 DBA。听起来您遇到的资源争用问题可能超出了简单的索引调整。这可能是一个更大问题的征兆。 (可能是设计问题...否则资源限制。)

无论如何,祝你好运!

【讨论】:

    【解决方案3】:

    一些作者确实建议不要在identity 列上“浪费”CI,如果有其他有利于范围查询的替代方法。

    来自 MSDN Clustered Index Design Guidelines 应根据以下标准选择密钥

    1. 可用于常用查询。
    2. 提供高度的唯一性。
    3. 可用于范围查询。

    您的CourtOrderID 专栏符合2。您的PersonId13 相遇。由于大多数行最终都会添加uniqueifier,因此您不妨将其声明为唯一并使用PersonId,CourtOrderID,因为这将是相同的宽度,但更有用,因为将聚集索引键添加到所有 NCI 作为行定位器,这将允许它们覆盖更多查询。

    使用PersonId,CourtOrderID 作为 CI 的主要问题是可能会出现逻辑碎片(这尤其会影响您试图帮助的范围查询),因此您需要监控填充因子和碎片级别并执行索引维护更频繁。

    【讨论】:

      【解决方案4】:

      在以下链接中有解释:https://msdn.microsoft.com/en-us/ms190457.aspx

      集群

      • 聚集索引根据键值对表或视图中的数据行进行排序和存储。这些是索引定义中包含的列。每个表只能有一个聚集索引,因为数据行本身只能按一种顺序排序。

      • 表中的数据行按排序顺序存储的唯一情况是表包含聚集索引。当表具有聚集索引时,该表称为聚集表。如果表没有聚集索引,则其数据行存储在称为堆的无序结构中。

      非集群

      • 非聚集索引具有与数据行分开的结构。非聚集索引 c包含非聚集索引键值,每个键值条目都有一个指向包含键值的数据行的指针

      • 从非聚集索引中的索引行指向数据行的指针称为行定位器。行定位器的结构取决于数据页是存储在堆还是聚集表中。对于堆,行定位器是指向行的指针。对于聚簇表,行定位符是聚簇索引键。

      • 您可以将非键列添加到非聚集索引的叶级别,以绕过现有的索引键限制、900 字节和 16 个键列,并执行完全覆盖的索引查询。

        李>

      【讨论】:

        【解决方案5】:

        一些带有一些讨厌的选择的数据库,加入一个存储过程 - 唯一的区别是索引

        索引 - 集群与非集群

          891 rows
          10 sec
          NONCLUSTERED 
        
          OR
        
          891 rows
          14 sec
          CLUSTERED
        

        【讨论】:

          猜你喜欢
          • 2014-08-19
          • 2011-01-09
          • 1970-01-01
          • 1970-01-01
          • 2018-07-16
          • 2019-05-28
          • 1970-01-01
          • 2012-05-29
          • 2015-03-14
          相关资源
          最近更新 更多