【问题标题】:Sql Server Legacy Database To Clustered index or notSql Server Legacy Database To Clustered index 与否
【发布时间】:2011-04-01 21:21:48
【问题描述】:

我们有一个旧数据库,它是一个 sql server db(2005 和 2008)。

表中的所有主键都是唯一标识符。

这些表目前没有在它们上创建聚集索引,并且我们在只有 750k 记录的表上遇到了性能问题。这是我第一个使用唯一标识符作为唯一主键的数据库,我从未见过 sql server 的返回数据这么慢。

我不想在唯一标识符上创建聚集索引,因为它们不是连续的,因此在插入数据时会降低应用程序的速度。

我们无法删除用于远程站点记录身份管理目的的唯一标识符。

我曾考虑在表中添加一个大整数标识列,并在该列上创建聚集索引并包括唯一标识符列。

int identity - 保持插入速度的第一列 唯一标识符 - 确保应用程序按预期工作。

目标是提高身份查询和联表查询性能。

Q1:这会提高数据库的查询性能还是会减慢它的速度?

Q2:有没有我没有列出的替代方案?

谢谢 皮特

编辑:性能问题在于通过 select 语句快速检索数据,尤其是在将几个“事务性/变化”表连接在一起时。

编辑2:表之间的连接一般都在主键和外键之间,对于有外键的表,它们被包含在非聚集索引中,以提供覆盖范围更大的索引。

这些表都没有其他可以提供良好聚集索引的值。

我更倾向于在每个高负载表上添加一个额外的标识列,然后在聚集索引中包含当前的 Guid PK 列以提供最佳查询性能。

编辑 3: 我估计 80% 的查询是通过数据访问机制单独对主键和外键执行的。通常,我们的数据模型具有延迟加载的对象,这些对象在访问时执行查询,这些查询使用对象 id 和 PK 列。我们有大量用户驱动的数据排除/包含查询,它们使用外键列作为过滤器,基于类型 X 的标准排除以下 id。剩下的 20% 是 Enum (int) 或日期范围列上的 where 子句,系统中很少执行基于文本的查询。

在可能的情况下,我已经添加了覆盖索引来覆盖最繁重的查询,但到目前为止我仍然对性能感到失望。正如 bluefooted 所说,数据被存储为堆。

【问题讨论】:

  • 您目前在 uniqueidentifiers 上有一个非聚集索引吗?
  • 是的,我们在唯一标识符上有非聚集索引。
  • 由于您在该列上至少有一个索引,因此您已经在插入时产生了性能损失。根据表的结构,您可能只是能够删除非聚集索引并切换到聚集索引,而对您当前看到的内容几乎没有影响。
  • 我对聚集索引的理解是,数据是按照索引指定的顺序存储的,在非顺序 guid 的情况下,它对插入性能有很大的影响。然而,非集群只是指向不会显着降低插入性能的记录的指针。我将仔细检查这些信息并确保我的理解是正确的。
  • 彼得,这不是 100% 正确的。还必须对非聚集索引进行排序(请注意,对于所有这些索引,这是对每个页面进行排序,而不是与同一页面中的其他行相比,每个页面内的行)。确实,通常非聚集索引更窄,因此它们更有效,但是当您插入时,您仍然会在整个地方得到页面拆分。

标签: sql sql-server indexing clustered-index identity-column


【解决方案1】:

我不确定您的 GUID 来自哪里,但如果它们是在插入期间生成的,那么在 SQL Server 中使用 NEWSEQUENTIALID() 而不是 NEWID() 将帮助您避免在插入期间出现碎片问题。

关于聚簇索引的选择,正如 Kimberly L. Tripp 所说 here:“选择聚簇索引的最重要因素是它是唯一的、狭窄的和静态的(不断增加还有其他好处,可以最大限度地减少拆分) 。”与 INT 甚至 BIGINT 相比,GUID 无法满足狭义要求。

Kimberly 在GUIDs as PRIMARY KEYs and/or the clustering key 上也有一篇很棒的文章。

【讨论】:

  • 标识符是通过 .Net Frameworks Guid.NewGuid() 生成的;因为该系统的体系结构是为了让对象生成自己的 id 而构建的。 (又是一个遗留系统。)
【解决方案2】:

您没有说明您的性能问题是什么。如果执行最差的操作是 INSERT,那么您的解决方案可能是正确的。如果是其他问题,那么我会看看聚集索引如何提供帮助。

您可能会查看表上的现有索引以及使用它们的查询。您可以选择一个索引,虽然会稍微降低 INSERT,但可以为当前的性能问题区域提供更大的好处。

【讨论】:

  • 你说得对,鲍勃我编辑了这篇文章。问题是当我们查询更多事务表时(即变化最多的不是静态表)。如果我们将多个事务表连接在一起,情况会更加复杂。
【解决方案3】:

如果您的表上没有聚集索引,则它被存储为堆而不是 b 树。在 SQL Server 中堆数据访问绝对是残酷的,所以你肯定需要添加一个聚集索引。

我同意您的分析,即 GUID 列对于聚类来说是一个糟糕的选择,尤其是因为您无法使用 NEWSEQUENTIALID()。如果您愿意,您可以创建一个新的人工整数键,但如果有另一列或列组合作为聚集索引有意义,那也可以。

您是否有经常用于范围扫描的字段?哪些列用于连接?除了 GUID 之外,是否存在也唯一标识行的列组合?发布数据模型的样本将帮助我们建议一个好的聚类候选者。

【讨论】:

  • Blue 很遗憾,我无法发布数据模型,因为我的公司对这类事情非常严格。在某些表中,有用于范围扫描的日期列。通常主键(guids)和外键(guids)用于连接,纯文本列上没有任何连接。我想知道使用创建的日期,但我只是在最后一个版本中添加了它,因此并非每一行都有这个值。我认为添加打开身份的人工整数键是我将采取的路径。 guid 是每个表中的 PK。
  • 日期通常是聚类键的良好候选者,尤其是在查询经常受日期范围限制的情况下。如果您只是添加它,我想它不会经常使用,但至少在创建日期后,您可以确保有序插入,从而最大限度地减少页面拆分和碎片。我对人工密钥的唯一担心是,除非您更改数据模型以加入新密钥而不是 GUID,否则它可能永远不会有用。
  • 无论您最终选择什么,请务必检查您的非聚集索引。如果您的 GUID 索引仅包含 GUID 列,则它可能不是非常有用。您可能想研究在 INCLUDE 子句中添加一些列以涵盖最常见的查询。
  • 哦,抱歉,我刚刚阅读了您关于覆盖索引的编辑 :)
  • 蓝色,在一个最多有 10 列,最多有 100 条记录的表上(仅在设置期间编辑),聚集索引是否可以在该表的 pk 上,即使它是向导?对于这些类型的表格,保存速度并不重要。
【解决方案4】:

我不是 100% 清楚:您的第一访问模式是按 GUID 还是按其他列查询表?以及在加入其他表时,最常使用哪些列(和数据类型)?

在我进一步了解如何使用这些 GUID 之前,我真的无法给你任何可靠的建议。我知道您说过它们是主键,但这并不能保证它们被用作查询或连接的主要条件。

更新

现在我知道的更多了,我有一个疯狂的建议。将这些表聚集在 GUID 上,但将填充因子设置为 60%。这将改善页面拆分问题,并为您提供更好的对这些小狗的查询性能。

至于使用 Guid.NewGuid(),看来您毕竟可以在 C# 中执行顺序 GUID。我在 SO 上找到了以下代码:

[DllImport("rpcrt4.dll", SetLastError = true)]
static extern int UuidCreateSequential(out Guid guid);

public static Guid SequentialGuid()
{
    const int RPC_S_OK = 0;
    Guid g;
    if (UuidCreateSequential(out g) != RPC_S_OK)
        return Guid.NewGuid();
    else
        return g;
}

newsequentialID() 实际上只是 UuidCreateSequential 的一个包装器。我敢肯定,如果您不能直接在客户端上使用它,您可以找到一种方法来快速往返服务器以从那里获取新的顺序 ID,甚至可以使用“分配器”表和存储过程来完成这项工作。

【讨论】:

  • 填充因子绝对是一种可能性,尽管它会再次使您的索引膨胀。在您的聚集索引中拥有 GUID 键并不理想,但由于您已经被 GUID 困住并且它们被用于您的大多数连接,您可能不得不使用它。我认为底线是你需要做一些测试来找出最好的方法。您有可以用来尝试不同方法的测试系统吗?
  • 我同意使用那些巨大的 GUID 很糟糕,并且通过减少填充因子来降低每页的行数是不幸的,但如果他想以读取性能为代价来提高更新性能,那就是这样去。这甚至不是一个直接的命题,因为页面拆分已经降低了页面行密度......
  • 是的,我听到你了,这绝对不是一个简单的问题,但他所说的目标实际上是提高读取性能:“目标是提高标识查询和连接表查询的性能。”不幸的是,在不查看实际执行计划的情况下很难提出一般性建议。在这种情况下,我认为最好的办法是测试几种不同的策略,看看哪种策略最有效。
猜你喜欢
  • 2015-11-04
  • 2019-09-27
  • 2011-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多