【问题标题】:Removing a Primary Key (Clustered Index) to increase Insert performance删除主键(聚集索引)以提高插入性能
【发布时间】:2011-11-08 01:16:30
【问题描述】:

我们一直在遇到 SQL 超时问题,并发现瓶颈是审计表 - 我们系统中的所有表都包含插入、更新和删除触发器,这些触发器会导致新的审计记录。

这意味着审计表是系统中最大和最繁忙的表。然而数据只进不出(在此系统下),因此不需要select 性能。

运行select top 10 返回最近插入的记录,而不是“第一条”记录。 order by 当然可以,但我希望 select top 应该根据它们在磁盘上的顺序返回行 - 我希望这会返回最低的 PK 值。

有人建议我们删除聚集索引,实际上也删除主键(唯一约束)。正如我之前提到的,在这个系统中,不需要从这个表中select

聚集索引会对表产生什么样的性能影响?拥有一个无索引、非集群、无键表的(非选择)后果是什么?还有其他建议吗?

编辑

我们的审计涉及 CLR 功能,我现在正在使用和不使用 PK、索引、FK 等进行基准测试,以确定 CLR 功能和约束的相对成本。

经调查,性能不佳与insert 语句无关,而是与协调审计的CLR 函数有关。移除 CLR 并使用直接的 TSQL proc 后,性能提高了 20 倍。

在测试过程中,我还确定聚集索引和标识列对插入时间的影响很小或没有影响,至少相对于发生的任何其他处理而言。

// updating 10k rows in a table with trigger

// using CLR function
PK (identity, clustered)- ~78000ms
No PK, no index - ~81000ms

// using straight TSQL
PK (identity, clustered) - 2174ms
No PK, no index - 2102ms

【问题讨论】:

    标签: sql-server-2008 primary-key clustered-index database-performance


    【解决方案1】:

    Tibor Karaszi 的博客SQLblog.com 上提供了一个很棒的测试脚本和该场景的描述

    我的数字与他的不完全匹配 - 我发现批处理语句的差异更多,而不是每行语句。

    在行数约为 100 万的情况下,我相当一致地在聚集索引上获得了单行插入循环,其执行速度比在非索引上稍快(聚集在非索引上大约需要 97%)。

    相反,批量插入(10000 行)更快地插入非索引而不是聚集索引(从 75%-85% 的聚集插入时间)。

    clustered - loop        - 1689
    heap      - loop        - 1713
    clustered - one statement - 85
    heap      - one statement - 62
    

    他描述了每次插入时发生的情况:

    堆: SQL Server 需要找到该行的位置。为此它 为堆使用一个或多个 IAM 页,并交叉引用这些 到数据库文件的一个或多个 PFS 页。 IMO,应该有 在这里可能会产生显着的开销。甚至更多,与许多 用户敲打同一张桌子我可以想象阻止(等待)反对 PFS 和可能还有 IAM 页面。

    集群表:现在,这非常简单。 SQL 服务器导航 聚集索引树并找到该行的位置。由于这是 一个不断增加的索引键,每一行都会走到表的末尾 (链表)。

    【讨论】:

      【解决方案2】:

      根据索引女王 Kimberly Tripp 的说法,在表上使用聚集索引实际上有助于 INSERT 性能:

      聚集索引辩论继续

      • 在聚簇表中插入速度更快(但仅限于“右侧” 聚集表)而不是与堆相比。这里的主要问题是 在 IAM/PFS 中查找以确定堆中的插入位置 比在聚集表中慢(插入位置已知, 由聚集键定义)。插入时插入速度更快 定义顺序的表 (CL) 以及该顺序所在的位置 不断增加。

      来源:名为The Clustered Index Debate Continues....的博文

      【讨论】:

      • 我发现这一点尤其适用于表格大小的增加。
      【解决方案3】:

      我的原始理解是,即使是 INSERT 操作,使用聚集索引通常也比使用堆更快。此外,聚集索引的磁盘空间要求更低。

      一些有趣的测试/场景可能会为您的特定情况提供一些启示:http://technet.microsoft.com/en-us/library/cc917672.aspx

      【讨论】:

        【解决方案4】:

        一个表没有一个键?甚至没有自动递增代理键? :(

        只要键是单调递增,插入时的索引维护应该是好的——它只是“在末尾添加”。 “集群”仅表示表的物理布局遵循索引(因为数据是索引的一部分)。只要索引没有碎片化(请参阅单调递增位),那么集群本身/数据就不会在逻辑上碎片化,这不应该是性能问题。 (如果有更新,则集群情况略有不同:更新的记录可能会“增长”并导致碎片化。)

        我的建议是,如果这是选择的路线,那么... 用实际数据/负载对其进行基准测试,然后决定是否有必要提出此类建议。很高兴看到是否已决定进行此更改,以及为什么。

        编码愉快。


        此外,除了来自ORDER BY 之外的任何对订单的依赖都存在设计缺陷。它现在可能可以工作,但它是一个实现细节,并且可能会以微妙的方式发生变化(就像不同的查询计划一样简单)。使用自动递增键,ORDER BY DESC 始终会产生正确的结果(请记住,可以跳过自动递增 ID,但除非“重置”,否则它们将始终根据插入顺序递增)。

        【讨论】:

        • 干杯。我不依赖顺序,我只是在管理器中使用它来证明索引不能确保行以一致的方式放置在磁盘上。
        猜你喜欢
        • 2010-10-09
        • 2023-03-12
        • 2023-03-23
        • 1970-01-01
        • 2012-04-30
        • 2017-03-06
        • 1970-01-01
        • 2010-12-30
        • 2011-01-26
        相关资源
        最近更新 更多