【问题标题】:ADO.net SqlTransaction improves performanceADO.net SqlTransaction 提高性能
【发布时间】:2011-02-23 12:45:48
【问题描述】:

我正在做一些涉及将一批记录插入 Sql 数据库的工作。批处理的大小会有所不同,但为了论证,我们可以说每 5 秒有 5000 条记录。不过可能会少一些。多个进程将写入此表,没有任何内容从中读取。

我在快速测试期间注意到的是,围绕整个批处理插入使用 SqlTransaction 似乎可以提高性能。

例如

SqlTransaction trans = Connection.BeginTransaction()
myStoredProc.Transaction = trans;
sampleData.ForEach(ExecuteNonQueryAgainstDB);
transaction.Commit();

我对能够回滚我的更改不感兴趣,所以我不会真正考虑使用事务,除非它似乎可以提高性能。如果我删除此事务代码,我的插入时间将从 300 毫秒缩短到 800 毫秒左右!

这样做的逻辑是什么?因为我的理解是事务仍然将数据写入数据库但锁定记录直到它被提交。我本来预计这会产生开销......

我正在寻找的是执行此插入的最快方法。

【问题讨论】:

  • 如果你只是写它,你还可以指定trans.IsolationLevel = IsolationLevel.Chaos(最低级别),这样你的事务就不会锁定其他并发事务。

标签: c# sql-server ado.net


【解决方案1】:

提交是花费时间的。如果没有显式事务,则每个执行的查询都有一个事务。使用显式事务,不会为您的查询创建额外的事务。因此,您有一笔交易与多笔交易。这就是性能改进的来源。

【讨论】:

  • 我认为提交实际上很便宜;回滚是昂贵的。我希望在设置大量事务时确实是开销,但在 start,而不是 end - IIRC.
【解决方案2】:

如果您正在寻找插入/加载数据的快速 wqay,请查看 SqlBulkCopy Class

【讨论】:

  • SqlBulkCopy 的问题是您需要了解表结构。同意这是最快的方式,但差距很大。
【解决方案3】:

你得到的是完全正常的。

如果您使用通常的隔离级别(比如提交或快照),那么当您不使用事务时,数据库引擎必须在每次插入时检查冲突。也就是说,它必须确保每当有人从该表中读取(使用SELECT *)例如,它不会得到脏读,也就是说,保持插入,以便在插入本身发生时没有其他人发生正在阅读。

也就是说,锁定、插入行、解锁、锁定、插入行、解锁等等。

当您将所有内容封装在一个事务中时,您有效实现的就是在提交阶段将这一系列“锁定”和“解锁”减少为一个。

【讨论】:

  • 我猜这种方法的缺点是表在事务期间被锁定?如果多个进程试图写入该表,这些事务是否会有效地排队,或者不需要,因为这些插入永远不会更新或删除现有行?
  • 需要锁定表,因为 select * 影响需要所有行,你不能只是在中间打断。无论如何,这并不意味着需要很长时间。我不知道任何具体的实现,但可以想象你可以在内存中构造一个表副本,然后如果有足够的内存就进行交换,这将非常快。
【解决方案4】:

我刚刚写完一篇blog post,介绍了通过明确指定事务的开始和结束位置可以获得的性能提升。

使用 Dapper,我观察到事务将批量插入时间减少到原始时间的 1/2,批量更新时间减少到原始时间的 1/3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-24
    • 1970-01-01
    • 1970-01-01
    • 2013-02-12
    • 2021-12-18
    • 2011-05-07
    • 2016-04-19
    • 2016-10-07
    相关资源
    最近更新 更多