【问题标题】:SQL Server: ~2000 Heap Tables all using GUID Uniqueidentifier - Possible Clustered Indexing?SQL Server:~2000 个堆表都使用 GUID 唯一标识符 - 可能的聚集索引?
【发布时间】:2018-03-03 22:34:28
【问题描述】:

我刚刚接管了一个包含大约 2200 个表的数据库。其中超过 2000 个没有聚集索引(有些根本没有索引)。

所有表都已配置为使用 GUID 作为唯一标识符。

仅查看查询计划,我可以看到发生了许多表扫描。大多数搜索使用唯一标识符进行搜索。

我想知道在 GUID 上有一个聚集索引是否比根本没有聚集索引更好。我想在 16 字节列上的聚集索引将不可避免地导致碎片。

可以说我可以聚集在其他列上,但大多数搜索倾向于通过 GUIDS 搜索或加入。

非常欢迎任何建议。我从来没有见过这么多的GUID!

【问题讨论】:

  • 一如既往——视情况而定。这个数据库是重读轻写,还是相反?有很多查询只需要一行,还是有很多查询需要扫描整个表?如果有许多行查找和许多插入,一种方法是添加一个标识,在该标识上进行聚类,然后将非聚集索引添加到 GUID 列。该索引会分片,但如果它只用于行查找,这没什么大不了的。
  • 如果 GUID 是由 NEWID() 默认约束生成的,则该框中的另一个技巧是将它们修补到 NEWSEQUENTIALID()。这至少会减少新插入的碎片。
  • 感谢 Jeroen - 我的另一个困境是我只是其中的 DBA,并且添加字段(在本例中为身份)的权力是由第 3 方开发人员负责的。根据我最近与他们的谈话,我很确定他们将不愿意添加这样的功能!他们真的可以在 INT 上使用 Identity,但不确定他们为什么要使用这么多 GUIDS。
  • 明确一点:您不需要说服开发人员开始使用整数 ID。如果有很多行查找,在由数据库自动生成但完全未使用的顺序 ID 上添加聚集索引,以及在 GUID 上添加非聚集索引已经可以改善问题。当然,如果他们要求根本不改变表格,你的工作就更难了……但是他们应该为自己的烂摊子负责。您只能从数据库层本身做很多事情。
  • 从来没有一个更真实的词!!!感谢您的建议

标签: sql-server indexing guid clustered-index


【解决方案1】:

一般来说,我建议将identity 列作为主键并将其用于集群。这也是joins 更好的选择。

为什么?首先,身份密钥通常比唯一 ID 短。因此,外键引用和索引更小。

更重要的是,inserts 将始终位于表格的“末尾”。使用 GUID 时,插入通常会导致碎片。如果要插入行,我会说 GUID 上的二级索引可能比聚集索引更好(碎片仅在索引中)。

有 2000 个表,我怀疑你会改变结构。您可以使用newsequentialid() 来改善碎片。

【讨论】:

  • 感谢 Gordon,我一定会研究 newsequentialid() 的可能性,看起来像是一个改进。我不确定我是否会被允许添加一个标识列,因此必须充分利用我所拥有的。我可以添加索引、统计信息和调整查询……但我不能更改表的结构,因此为什么我想知道是否应该在这些表上聚集?
  • 假设您不能将 identity 列作为 PK。这给我们留下了以下之一:GUID PK 上的集群(=碎片),非 PK identity 列上的集群,其唯一目的是集群,或者将其保留为堆表。后两者如何比较?聚集在从未实际直接用于查找/连接的列上的表是否比堆表更好?
  • @RomanStarkov 。 . .问题应该作为问题而不是评论提出。
  • 我考虑过这一点,但我希望它会作为这个副本的副本被关闭......即使这个特殊的微妙之处还没有被涵盖。
【解决方案2】:

具有随机值的GUID列通常不是聚集索引的最佳选择,因为它可能是index fragmentation的根本原因:

  1. 数据库的预读机会将无效;
  2. 插入操作的成本太高了,因为在这种情况下你会得到很多page split overhead;

您可以通过 3 种方式来应对这种情况:

  1. 调度计划index reorganizing and rebuilding这将减少索引碎片并自动改善您的统计信息;
  2. 使用 newsequantialid 用于生成该列的值;
  3. 生成 数据库之外的 GUID 值(Guid.Comb Identifier 是解决此问题的一个很好的例子 NHibernate)。

【讨论】:

    【解决方案3】:

    这真的是对您对 Gordon 的好回答的问题的评论:

    首先,不要忘记检查索引 DMV 以查看正在使用(或未使用)的 DMV,并查看缓存中昂贵的查询计划以专注于将导致最多的表和查询疼痛。我希望这 2200 个表中的许多表都相对较小,即使从 guid 聚集索引中查询也能够非常快速地查找。

    对于那些未集群的表,在 guid 上集群会减少碎片,因为它会强制表的所有数据位于同一位置,而不是允许将页面放入下一个空闲范围并在整个表中分散表磁盘。这应该使一些 I/O 更有效率。

    检查您的填充因子是否足够低,以便您的常规索引重建提前避免页面拆分,尽管它也将取决于工作负载(OLTP 与 DW 和表的读/写比率)

    如果您的应用程序正在执行显式列选择/插入,那么您可以添加标识列而不会破坏任何内容。这允许您围绕身份进行聚类并向 guid 添加索引。这是否真的有帮助取决于新计划的相对(无效)效率。

    您可以考虑围绕非 guid 字段进行聚类,在该字段中查询会定期查找(例如,日期范围)并单独为该 guid 编制索引。 您必须更仔细地查看查询和相关性能。

    【讨论】:

    • 感谢 Simon,我认为需要在每个表的基础上执行正确的索引解决方案。从所有答案和我的其他研究来看,如果可能的话,似乎真的应该避免在 GUID 上进行聚类。我将与开发人员交谈,看看是否可以添加身份列。但是,如果我自己设计这些数据库,首先使用标识列就可以消除这种情况。
    猜你喜欢
    • 2010-10-23
    • 1970-01-01
    • 1970-01-01
    • 2010-11-23
    • 1970-01-01
    • 2010-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多