【问题标题】:How to Improve Entity Framework bulk insert如何改进实体框架批量插入
【发布时间】:2014-07-22 08:47:20
【问题描述】:

我有一个应用程序,它从多个套接字接收数据,然后将数据写入数据库。

我目前正在使用 EF 来执行此操作。我想知道如何提高效率。

我读到批量插入更快,所以我只每 500 个插入者保存对数据库的更改:

   db.Logs_In.Add(tableItem);
            if (logBufferCounter++ > 500)
            {
                db.SaveChanges();
                logBufferCounter = 0;
            }

现在我已经分析了应用程序,并且 74% 的工作由函数完成:System.Data.Enitity.DbSet'1[System._Canon].Add

有没有更好的插入方法?也许将 tableItems 排队到一个列表中,然后将整个列表添加到数据库上下文中。

或者也许我看错了,我应该完全避免使用 EntityFramework 来进行这种更高性能的插入?目前它是我的应用程序的瓶颈,如果我查看系统资源,SQL 似乎连眼皮都没有动。

所以我的问题:

1:如何在多次插入中实现最有效/最快的插入

2:如果 EF 可以接受,我该如何改进我的解决方案?

我使用的是 SQL Server 2012 企业版, 传入的数据是一个恒定的流,但是我可以缓冲它,然后如果这是一个更好的解决方案,我可以进行批量插入。

[编辑]

进一步解释场景。我有一个线程在 concurrentQueue 上循环,该线程从该队列中取出项目。然而,由于分贝插入是瓶颈。队列中通常有数千个条目,所以如果还有一种异步或并行方式,我可能会使用多个线程来进行插入。

【问题讨论】:

  • 这里stackoverflow.com/a/5942176/1663001关于高频插入的讨论非常好。
  • @DavidG,谢谢,如果我走 EF 路线,那真的很有帮助,我做出了更改建议,我的性能已经提高了 100 倍。
  • 太棒了,我希望它对你来说已经足够了。如果不是,那么 Marc 的答案就是要走的路。

标签: c# sql entity-framework insert bulkinsert


【解决方案1】:

对于涉及大量插入的场景,我倾向于“单独缓冲”(内存中、redis 列表等),然后作为批处理作业(可能每分钟或每几分钟)读取列表并使用SqlBulkCopy 尽可能高效地将数据放入数据库中。为了解决这个问题,我使用了fastmemberObjectReader.Create 方法,它将List<T>(或任何IEnumerable<T>)公开为IDataReader,可以输入SqlBulkCopy,公开T 的属性作为数据读取器中的逻辑列。那么,您需要做的就是从缓冲区中填充List<T>

但是,请注意,您需要考虑“出现问题”的情况;即如果插入中途失败,你会如何处理缓冲区中的数据?这里的一种选择是将SqlBulkCopy 放入一个 staging 表(相同的架构,但不是“实时”表),然后使用常规的INSERT 在您复制数据时一步完成知道它在数据库中 - 这使恢复更简单。

【讨论】:

  • +1 关于错误问题,是否有一些方法可以插入所有有效的,然后可能将失败的插入放入失败的表中?
  • @Zapnologica 取决于错误的性质。如果错误是您与 sql server 的连接在中途中断,那么...您将要做什么?事实上,因为SqlBulkCopy 没有告诉您它走了多远(更不用说告诉您日志文件的前滚部分中的内容,如果数据库服务器完全崩溃),您的选择是有限的。如果您可以在以后的重试中补偿重复项,那么“从头开始重做”策略是一种合理的策略。 “数据不是那么重要;我不在乎我们是否会从一批中丢失几行”策略有时也有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-07
  • 1970-01-01
  • 1970-01-01
  • 2020-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多