我有一个应用程序,它从多个套接字接收数据,然后将数据写入数据库。
我目前正在使用EF来执行此操作。我想知道如何提高效率。
我已经读过,执行批量插入更快,所以我每500个插件只保存对数据库的更改:
db.Logs_In.Add(tableItem);
if (logBufferCounter++ > 500)
{
db.SaveChanges();
logBufferCounter = 0;
}
现在我已经分析了应用程序,74%的工作由功能完成:System.Data.Enitity.DbSet'1[System._Canon].Add
有没有更好的方法来插入?也许将tableItems排队到List中,然后将整个列表添加到DB Context。
或许我正在看这一切都错了,我应该完全避免使用EntityFramework来获得更高性能的插件?目前它是我应用程序中的瓶颈,如果我查看系统资源,SQL似乎甚至不会让人眼前一亮。
所以我的问题:
1:我将以何种方式在多个插入上实现最有效/最快的插入
2:如果EF可以接受,我该如何改进我的解决方案?
我使用的是SQL Server 2012企业版, 传入的数据是一个恒定的流,但是如果这是一个更好的解决方案,我可以负担缓冲它然后执行批量插入。
[编辑]
进一步解释这个场景。我有一个循环在concurrentQueue上的线程,该队列从这个队列中取出项目。然而,由于db插入物是瓶颈的事实。队列中经常有数千个条目,所以如果还有异步或并行方式,我可以使用多个线程来进行插入。
答案 0 :(得分:4)
对于涉及大量插入的场景,我倾向于单独使用"缓冲区" (在内存中,或redis列表,或其他),然后作为批处理作业(可能每分钟,或每隔几分钟)读取列表并使用SqlBulkCopy
尽可能有效地将数据投入数据库。为了解决这个问题,我使用了fastmember的ObjectReader.Create
方法,该方法将List<T>
(或任何IEnumerable<T>
)公开为IDataReader
,可以将其输入SqlBulkCopy
,将T
的属性公开为数据读取器中的逻辑列。然后,您需要做的只是填充缓冲区中的List<T>
。
但是,请注意,您需要考虑&#34;出现问题&#34;场景;即如果插入失败了一半,你如何处理缓冲区中的数据?这里的一个选项是将SqlBulkCopy
放入 staging 表(相同的架构,但不是&#34; live&#34;表),然后使用常规INSERT
当你知道它在数据库中时,一步复制数据 - 这使得恢复变得更简单。