【问题标题】:How much does wrapping inserts in a transaction help performance on Sql Server?在事务中包装插入对 Sql Server 的性能有多大帮助?
【发布时间】:2010-10-06 00:47:12
【问题描述】:

好吧,假设我有 100 行要插入,每行大约有 150 列(我知道这听起来像很多列,但我需要将这些数据存储在一个表中)。插入将随机发生(即,每当一组用户决定上传包含数据的文件时),大约每月 20 次。然而,数据库将在持续负载下处理大型企业应用程序的其他功能。这些列是 varchars、ints 以及各种其他类型。

将这些插入包装在事务中(而不是一次运行一个)的性能增益是巨大的、最小的还是介于两者之间?

为什么?

编辑: 这是针对 Sql Server 2005 的,但如果有不同的说法,我会对 2000/2008 感兴趣。另外我应该提一下,我理解事务主要是为了数据一致性,但我想关注性能影响。

【问题讨论】:

  • 在 2000/2008 年之间,没有什么值得注意的差异。性能提升和事务一致性几乎总是相互矛盾的。架构设计、索引架构和存储方法/最佳实践将决定您的性能提升。处理数据时的第一条经验法则是,使您的数据请求和操作尽可能小和短 (OLTP)。然后进行相应的调整。规则是,不要在事务中放置大量记录活动,事务是为了一致性而不是为了“回滚”大批量信息。

标签: sql sql-server database performance transactions


【解决方案1】:

这取决于您所说的巨大,但它会有所帮助(这实际上取决于您正在执行的插入总数)。它将强制 SQL Server 在每次插入后不进行提交,这会及时加起来。插入 100 次后,您可能不会注意到增加太多,具体取决于数据库发生的频率和其他情况。

【讨论】:

    【解决方案2】:

    实际上可能会产生影响。事务的重点不在于您做了多少,而在于保持数据更新的一致性。如果您有需要一起插入并且相互依赖的行,那么这些记录就是您包装在事务中的记录。

    事务是为了让您的数据保持一致。这应该是您在使用事务时首先考虑的事情。例如,如果您从支票账户中借记(提款),您希望确保贷记(存款)也已完成。如果其中任何一个不成功,则应回滚整个“事务”。因此,这两个操作都必须包含在一个事务中。

    在进行批量插入时,将它们分解为 3000 或 5000 条记录,然后在集合中循环。 3000-5000 对我来说是一个很好的插入数字范围;除非您已经测试过服务器可以处理它,否则不要超过它。此外,我将在大约每 3000 或 5000 条插入记录时将 GO 放入批处理中。更新和删除我会将 GO 设置为 1000 左右,因为它们需要更多资源来提交。

    如果您使用 C# 代码执行此操作,那么在我看来,您应该构建一个批量导入例程,而不是通过编码一次执行数百万次插入。

    【讨论】:

    • 我正在尝试使用检查进行数百万次插入。也就是说,如果目标表中存在一行,则不要插入它。我正在考虑将每个插入放在自己的事务中。这会是一个严重的问题吗?谢谢。
    • @Steam MERGE INTO 怎么样?
    • @steam 大量使用“批处理”;或将其保留为单一的、正常的、原子的事务(就像我的回答一样)。如果您的数据源位于 SQL 之外,则将数据快速放入临时表(无索引/检查/等),并使用批处理;然后将其移动到可能有检查的其他表中。否则,禁用检查和索引,直到之后。关键提示:避免隐式事务,显式事务应该是经验法则...technet.microsoft.com/en-us/library/2009.02.logging.aspx
    • @JuliaHayward MERGE INTO 可能有点繁重,实际上在处理一致性方面存在一些已知问题 (mssqltips.com/sqlservertip/3074/…) 所以,要小心并测试结果;简单的使用很好,更复杂的 MERGE 使用可能会让你陷入困境。因此,也许尽可能使用普通语句,尤其是 VLDB 和大批量处理。我们正在进入想法的分支。 1) 用于交易,2) 批量处理大量记录。
    【解决方案3】:

    事务不是为了性能,而是为了数据完整性。根据实施情况,只有 100 行不会有任何性能增益/损失(它们只会被额外记录,因此它们都可以回滚)。

    关于性能问题的注意事项:

    • TA 将与其他查询交互
      • 写 TA 会锁定元组/页面/文件
    • 提交可能只是(取决于锁定协议)时间戳的更新
    • 可能会为 TA 写入更多日志(应该能够回滚 TA,但 DB 可能已经广泛记录,顺序记录很便宜)
    • 隔离程度(我知道可以在某些数据库中切换此级别 - 几乎没有人使用级别 3)

    总而言之:使用 TA 来确保完整性。

    【讨论】:

      【解决方案4】:

      正如其他人所说,事务与性能无关,而是与数据的完整性有关。

      话虽如此,当您只谈论每月插入大约 20 次 100 行数据(意味着每月 2000 条记录)时,以一种或另一种方式担心性能是愚蠢的。过早的优化是浪费时间;除非您反复测试了这些插入对性能的影响(尽可能小且不频繁)并发现它们是一个主要问题,否则不要担心性能。与您提到的其他服务器负载相比,它可以忽略不计。

      【讨论】:

      • 是的,我就是这么想的,但有人告诉我不是这样,这也是我问这个问题的部分原因。
      • 不,除了保持数据完整性之外,如果您将大量行插入在一起,事务确实会对性能产生影响。在单个事务中执行它们可以降低所需的总 IOPS。
      • @PratikSinghal:不在此发帖者问题的上下文中。插入的行数可以忽略不计。
      【解决方案5】:

      虽然事务是一种保持数据一致性的机制,但如果使用不当或过度使用,它们实际上会对性能产生巨大影响。我刚刚完成了blog post 上关于显式指定事务而不是让它们自然发生对性能的影响。

      如果您要插入多行并且每次插入都发生在自己的事务中,那么锁定和解锁数据会产生大量开销。通过将所有插入封装在单个事务中,您可以显着提高性能。

      相反,如果您对数据库运行许多查询并且还发生大量事务,它们可能会相互阻塞并导致性能问题。

      交易与业绩明确相关,无论其潜在意图如何。

      【讨论】:

      • 我正在尝试使用检查进行数百万次插入。也就是说,如果目标表中存在一行,则不要插入它。我正在考虑将每个插入放在自己的事务中。看完这篇,我就不以防万一了。
      • @KenWhite 的回答说事务不会影响性能。所以,我仍然不确定哪个是正确的。
      • @blasto 您能做的最好的事情就是亲自尝试一下。当我进行测试时,我发现它通过在单个事务中执行许多插入而不是相同数量的插入每个具有自己的事务来减少一半的时间。 cf blog.staticvoid.co.nz/2012/04/… 也看到这个问题stackoverflow.com/questions/5091084/…
      • 我现在刚刚尝试过 - 在一个事务中,我尝试插入表中已经存在的 30K 行。它需要的时间比以前长得多。我认为尽管在必要的列上有索引,但还是会发生这种情况。
      • 表上的索引实际上可以抵消性能。在插入时,会发生对索引的更新(时间和开销)。也许在同一个动作中使用 EXISTS、insert 和 EXISTS 可能很难。 SHY远离一次交易做30K,做3K-5K。更新索引时,统计信息会变得更加陈旧。有时,在脚本的中间,执行索引碎片整理或更新统计信息(可能轻而快 2-5%)。或者,如果您只是在执行 INSERTS,请考虑将表上的 FILLFACTOR 和索引增加到(80 或 70)以给它一些空间以避免拆分页面。这需要时间,坚持下去。
      【解决方案6】:

      实际上 - 非常。大插入,100++(前提是您将 mysql 配置为增加查询大小和事务大小以支持巨大的查询/事务,抱歉不记得确切的变量名称) - 插入时间通常可以快 10 倍甚至更多更多

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-06
        • 2010-09-07
        相关资源
        最近更新 更多