实体框架插入性能

3

我正在使用Entity Framework和Azure Sql数据库进行测试。

插入1条记录需要400毫秒,插入20条记录需要2500毫秒。

使用EF插入1条记录需要400毫秒似乎有点慢。

EF的正常性能率是多少?

我是否做错了什么?

我知道批量插入可以提高性能,但我认为单个插入应该可以更快吧!?

var start = DateTime.Now;
testdbEntities testdbEntities = new testdbEntities();

for (int i = 0; i < 20; i++)
    testdbEntities.Users.Add(new User{Name = "New user"});

testdbEntities.SaveChanges();

var end = DateTime.Now;
var timeElapsed = (end - start).TotalMilliseconds;

你的表上有索引吗?你的网络连接速度如何?插入是在本地还是在 Azure 服务器上生产时进行的? - krillgar
这是一个全新的数据库和表。我的上传速度为50Mbit。在Azure上,插入几乎与本地生产环境相同。 - redlaz
你可能拥有50mbit的上传速度 - 但延迟是多少呢?如果你距离Azure数据库100毫秒,那可不是无关紧要的。 - TomTom
与生产环境相比,这并没有太大的区别。 - redlaz
是的,我已经切换到秒表了。谢谢。 - redlaz
显示剩余2条评论
4个回答

3

所有常见的技巧,如:

  • 将AutoDetectChangesEnabled设置为false
  • 使用AddRange而非Add
  • 等等

就像你已经注意到的那样,这些技巧不起作用,因为性能问题不在于Entity Framework,而在于SQL Azure

SQL Azure可能一开始看起来很酷,但除非您支付了非常好的高级数据库层,否则它是非常慢的。

正如Evk建议的那样,您应该尝试执行一个简单的SQL命令,例如"SELECT 1",您会发现这可能需要超过100毫秒,这太慢了。

解决方案:

  • 升级到更好的SQL Azure层
  • 远离SQL Azure

免责声明:我是项目Entity Framework Extensions的所有者

另一个解决方案是使用这个库,可以批量处理多个查询/批量操作。然而,即使这个库非常快,您仍需要更好的SQL Azure层,因为在您的情况下每个数据库往返需要超过200毫秒。


远离从来不是一个好的解决方案,除非问题是普遍存在的。 - TheGameiswar
最近有人注意到性能有所提升吗?我使用E.F.将数据插入Azure SQL,最近发现性能显著提高,而我并没有做出任何更改。 - donquijote
你好@donquijite,如果你不使用我们的库,这可能只是由于延迟问题。例如,服务器或数据库可能已升级到最新版本,这可能显著减少了延迟时间,并以同样的方式提高了性能。 - Jonathan Magnan

1
每次插入都会有一个提交并导致日志硬化(刷新到磁盘)。在批量写入的情况下,这可能不会导致每个插入的一次刷新(直到日志缓冲区满为止)。因此,尝试以某种方式批处理结果,例如使用TVFs。

0
大多数EF应用程序使用持久化无知POCO实体和快照更改跟踪。这意味着实体本身没有代码来跟踪更改或通知上下文更改。
当使用大多数POCO实体时,如何确定实体已更改(因此需要发送哪些更新到数据库)由Detect Changes算法处理。Detect Changes通过检测实体的当前属性值与查询或附加实体时存储在快照中的原始属性值之间的差异来工作。
快照更改检测在将每个实体添加到Entity Framework跟踪图时复制每个实体。然后,随着实体的更改,将比较每个实体与其快照以查看任何更改。这是通过调用DetectChanges方法来完成的。关于DetectChanges需要知道的重要信息是,每次调用它都必须遍历所有跟踪的实体,因此您在上下文中拥有的内容越多,遍历所需的时间就越长。
Auto Detect Changes所做的是插入上下文中发生的事件,并在发生事件时调用detect changes。
无论何时您添加一个新的用户对象,EF都会在内部跟踪它,并将新添加对象的当前状态保存在其快照中。 对于批量插入操作,EF将首先将所有记录插入到数据库中,然后调用DetectChanges函数。因此,批量插入所需的执行时间为(插入所有记录所需的时间+更新EF上下文所需的时间)。
通过禁用AutoDetectChanges,您可以使DB插入相对更快。因此,您的代码将如下所示:
using (var context = new YourContext()) 
{ 
    try 
    { 
        context.Configuration.AutoDetectChangesEnabled = false; 

        // do your DB operations
    } 
    finally 
    { 
        context.Configuration.AutoDetectChangesEnabled = true; 
    } 
}

0

我试过了,对于单个插入没有什么明显的改进。 - redlaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接