2011-02-23 62 views
2

我正在做一些涉及将一批记录插入Sql数据库的工作。批处理的大小会有所不同,但为了争论起见,我们可以每5秒说出5000条记录。虽然它可能会少一些。多个进程将写入此表,没有任何数据正在读取。ADO.net SqlTransaction提高了性能

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

例如

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

我没有兴趣在回滚我的变化,所以我不会真的只是它似乎提高性能使用事务考虑的能力。如果我删除这个事务代码,我的插入从300ms到800ms左右!

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

我在找什么是做这个插入的最快方法。

+0

如果你只写它,你也可以指定' trans.IsolationLevel = IsolationLevel.Chaos'(最低级别),所以你的事务不会锁定其他并发事务。 – Albireo 2011-02-23 12:58:27

回答

5

如果你正在寻找一个快速wqay插入/加载数据看看SqlBulkCopy Class

+0

SqlBulkCopy的问题是你需要知道表结构。同意这是最快的方式,虽然相当大的余地。 – user630190 2011-02-23 14:45:22

7

提交是花费时间。如果没有明确的事务处理,则每个查询都有一个事务执行。使用显式事务,不会为您的查询创建额外事务。所以,你有一个交易与多个交易。这就是性能改进的源泉。

+1

我以为这个提交很便宜,实际上;回滚是昂贵的。我预计在建立大量交易时确实会有开销,但在* start *,而不是* end * - IIRC。 – 2011-02-23 13:09:50

2

什么你得到是完全正常的。

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

这将意味着,锁定,插入行,解锁,锁定,插入行,解锁等。

当你将所有这些封装在一个事务中时,你实际上正在实现的是将一系列“锁定”和“解锁”减少到提交阶段中的一个。

+0

我猜这种方法的缺点是表被锁定在交易的持续时间?如果多个进程试图写入这个表,那么这些事务将被有效地排队或不需要,因为这些插入永远不会更新或删除到现有的行? – user630190 2011-02-23 14:03:44

+0

需要锁定表格,因为select *会影响所有行,所以不能在中间打断。无论如何,这并不意味着需要很长时间。我不知道任何具体的实现,但可以想象,你可以构建一个内存副本的表,然后只是交换,如果有足够的内存,这将是非常快的。 – 2011-02-23 16:03:48

1

我刚写完blog post就可以通过明确指定事务开始和结束的位置来获得性能提升。

随着小巧玲珑我观察交易切削批量插入下降为1/2原来的时间和批量更新时间下降到原来时间的1/3