批量插入花费比使用Dapper预期更长的时间

读完这篇文章之后,我决定仔细看看我使用Dapper的方式。

我在一个空的数据库上运行这个代码

var members = new List<Member>(); for (int i = 0; i < 50000; i++) { members.Add(new Member() { Username = i.toString(), IsActive = true }); } using (var scope = new TransactionScope()) { connection.Execute(@" insert Member(Username, IsActive) values(@Username, @IsActive)", members); scope.Complete(); } 

花了大约20秒。 这是2500插入/秒。 不错,但不是很好,或者考虑到博客是实现45k插入/秒。 在Dapper中有更有效的方法吗?

此外,作为一个方面说明,通过Visual Studiodebugging器运行此代码需要3分钟! 我觉得debugging器会稍微减慢一点,但我真的很惊讶,看到这么多。

UPDATE

所以这

 using (var scope = new TransactionScope()) { connection.Execute(@" insert Member(Username, IsActive) values(@Username, @IsActive)", members); scope.Complete(); } 

和这个

  connection.Execute(@" insert Member(Username, IsActive) values(@Username, @IsActive)", members); 

都花了20秒。

但是这花了4秒钟!

 SqlTransaction trans = connection.BeginTransaction(); connection.Execute(@" insert Member(Username, IsActive) values(@Username, @IsActive)", members, transaction: trans); trans.Commit(); 

使用这种方法,我能够达到的最好效果是在4秒钟内完成5万个logging

 SqlTransaction trans = connection.BeginTransaction(); connection.Execute(@" insert Member(Username, IsActive) values(@Username, @IsActive)", members, transaction: trans); trans.Commit(); 

我最近偶然发现了这个问题,注意到TransactionScope是在连接打开之后创build的(我认为这是因为Dappers Execute不像查询那样打开连接)。 根据这里的答案Q4: https : //stackoverflow.com/a/2886326/455904不会导致连接被TransactionScope处理。 我的同事做了一些快速testing,在TransactionScope之外打开连接大大降低了性能。

所以改为以下应该工作:

 // Assuming the connection isn't already open using (var scope = new TransactionScope()) { connection.Open(); connection.Execute(@" insert Member(Username, IsActive) values(@Username, @IsActive)", members); scope.Complete(); } 

我发现所有这些例子都不完整。

下面是一些在使用后正确closures连接的代码,并且正确地使用了事务范围来增强Excecute性能,这是基于这个线程中最近更好的答案。

 using (var scope = new TransactionScope()) { Connection.Open(); Connection.Execute(sqlQuery, parameters); scope.Complete(); } 

对我来说最快的变种:

 con.Execute(string.Format(@"insert into Member(Username, IsActive) {0}", string.Join(" union all ", members.Select(x => string.Format("select '{0}','{1}'", x.Username, x.IsActive))))); 

这就像生成sql一样:

 INSERT TABLENAME (Column1,Column2,...) SELECT 'Column1Row1Value','Column2Row1Value'... UNION ALL SELECT 'Column1Row2value','Column2Row2Value'... UNION ALL SELECT 'Column1Row3value','Column2Row3Value'... 

这个查询的工作更快,因为sql增加了一组行,而不是一次添加1行。 瓶颈不是写数据,而是写日志中的内容。

另外,请查看最小化日志logging的规则。