【问题标题】:Clustered index - multi-part vs single-part index and effects of inserts/deletes聚集索引 - 多部分与单部分索引以及插入/删除的影响
【发布时间】:2011-02-24 20:39:30
【问题描述】:

这个问题是关于当插入完成时,聚集索引中数据的重组会发生什么。我认为在具有聚集索引的表上进行插入应该比没有聚集索引的表更昂贵,因为在聚集索引中重新组织数据涉及更改磁盘上数据的物理布局。除了通过我在工作中遇到的示例外,我不知道如何表达我的问题。

假设有一个表 (Junk),并且对该表执行了两个查询,第一个查询按名称搜索,第二个查询按名称和某事搜索。当我在数据库上工作时,我发现该表已经创建了两个索引,一个用于支持每个查询,如下所示:

--drop table Junk1
CREATE TABLE Junk1
(
    Name char(5),  
    Something char(5),
    WhoCares int
)

CREATE CLUSTERED INDEX IX_Name ON Junk1
(
    Name
)

CREATE NONCLUSTERED INDEX IX_Name_Something ON Junk1
(
    Name, Something
)

现在,当我查看这两个索引时,似乎 IX_Name 是多余的,因为 IX_Name_Something 可用于任何希望按名称搜索的查询。所以我会消除 IX_Name 并将 IX_Name_Something 改为聚集索引:

--drop table Junk2
CREATE TABLE Junk2
(
    Name char(5),  
    Something char(5),
    WhoCares int
)

CREATE CLUSTERED INDEX IX_Name_Something ON Junk2
(
    Name, Something
)

有人建议应保留第一个索引方案,因为它会导致更有效的插入/删除(假设无需担心 Name 和 Something 的更新)。这有意义吗?我认为第二种索引方法会更好,因为这意味着需要维护的索引更少。

如果您能深入了解这个具体示例或指导我了解有关维护聚集索引的更多信息,我将不胜感激。

【问题讨论】:

    标签: sql sql-server indexing clustered-index


    【解决方案1】:

    是的,当您的聚集索引不是最佳时,插入现有表(或其页面)的中间可能会很昂贵。最坏的情况是页面拆分:页面上的一半行必须移动到其他地方,并且索引(包括该表上的非聚集索引)需要更新。

    您可以通过使用正确的聚集索引来缓解这个问题——理想情况是:

    • 窄(只有一个字段,尽可能小)
    • 静态(永不改变)
    • 唯一(这样 SQL Server 就不需要在行中添加 4 字节唯一符)
    • 不断增加(如 INT IDENTITY)

    您需要一个窄键(理想情况下是单个 INT),因为每个非聚集索引中的每个条目也将包含聚集键 - 您不想在集群中放置很多列键,你也不想把 VARCHAR(200) 之类的东西放在那里!

    随着聚集索引的不断增加,您将永远不会看到页面拆分的情况。您可能遇到的唯一碎片来自删除(“瑞士奶酪”问题)。

    查看 Kimberly Tripp 关于索引的 excellet 博客文章 - 最值得注意的是:

    假设有一张桌子(垃圾)和 有两个查询完成 表中,第一个查询按 名称和第二个查询按 名字和东西。正如我正在努力 我发现的数据库 表已创建有两个 索引,一个支持每个查询, 像这样:

    这绝对没有必要 - 如果您在 (Name, Something) 上有一个索引,那么如果您仅搜索和限制 WHERE Name = abc 也可以使用该索引,并且同样可以使用该索引 - 拥有一个仅包含 Name 列的单独索引完全不需要,只会浪费空间(并且需要时间来保持最新状态)。

    所以基本上,您只需要在(Name, Something) 上建立一个索引,我同意您的看法 - 如果您在此表上没有其他索引,那么您应该能够将其设为聚集键。由于该密钥不会不断增加并且可能也会改变(对吗?),这可能不是一个好主意。

    另一种选择是引入代理 ID INT IDENTITY 并在其上集群 - 有两个好处:

    • 应该是一个好的集群键,包括不断增加的键 -> 页面拆分和 INSERT 操作的性能不会有任何问题
    • 您仍然可以获得拥有集群键的所有好处(请参阅 Kim Tripps 的博客文章 - 集群表几乎总是比堆更可取)

    【讨论】:

      【解决方案2】:

      有人建议应该保留第一个索引方案,因为它会导致更有效的插入/删除

      这是一个虚假的声明。有序数据是有序数据,会执行相同的 IO。

      SET STATISTICS IO ON
      -- your insert statement here
      

      【讨论】:

        【解决方案3】:

        您只能在一个列上创建聚集索引,而不是两个或更多列,因此请选择您的应用主要查询的列,例如客户全名的通配符查询等(请参阅discussion

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-28
        • 1970-01-01
        • 2011-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多