【问题标题】:SaveChanges takes anywhere from 40 to 60 seconds to save ~8000 context changesSaveChanges 需要 40 到 60 秒来保存约 8000 个上下文更改
【发布时间】:2013-03-19 14:46:34
【问题描述】:

设置:

  • 启用延迟加载的实体框架 4(模型优先,每个层次结构的表)。
  • 表格数量约为 40 个(并且没有表格的字段超过 15-20 个)。
  • SQL Server Express 2008(不是 r2)。
  • 不存在数据库触发器或任何其他类似的东西 - 它仅用于存储。所有的逻辑都在代码中。
  • 目前的数据库大小约为 2GB。
  • (主键是 Guid,通过Guid.NewGuid() 在代码中生成 - 如果这很重要)
  • 保存一个复杂的操作结果(生成一个复杂的对象图)需要 40 到 60 秒(SaveChanges 返回的数字约为 8000 - 大部分是添加的对象和一些修改的)。
  • 在同一台计算机上使用空(或几乎空)数据库保存相同的操作结果通常需要大约 1 秒。

似乎影响此问题的唯一变量是数据库大小。但请注意,我只测量Context.SaveChages() 调用(所以即使我在某处有一些奇怪的迟缓查询也不应该影响这个问题)。

感谢任何关于为什么此操作可能会持续这么长时间的建议。

更新 1

澄清一下 - 执行需要 40-60 秒的代码是(仅当数据库大小约为 2gb 时才需要这么长时间):

Stopwatch sw = Stopwatch.StartNew();
int count = objectContext.SaveChanges(); // this method is not overridden
Debug.Write(sw.ElapsedMilliseconds); // prints out 40000 - 60000 ms
Debug.Write(count); // I am testing with exactly the same operation and the
                    // result always gives the same count for it (8460)

空 DB 的相同操作大约需要 1000 毫秒(同时仍然给出相同的计数 - 8460)。因此问题是 - 数据库大小如何影响SaveChanges()

更新 2

运行性能分析器表明主要瓶颈(从“代码角度”)是以下方法:

Method:   static SNINativeMethodWrapper.SNIReadSync
Called:    3251 times
Avg:         10.56 ms
Max:        264.25 ms
Min:          0.01 ms
Total:    34338.51 ms

更新 3

数据库中的所有 PK 和 FK 都有非聚集索引。我们使用随机 Guid 作为代理键(不是顺序的),因此碎片总是处于非常高的水平。我尝试在重建所有数据库索引后立即测试执行有问题的操作(所有索引的碎片小于 2-3%),但似乎并没有以任何方式改善这种情况。

此外,我必须说,在有问题的操作期间,该过程涉及的一张表大约有 400 万行(这张表有很多插入)。 SQL Profiler 显示对该表的插入可以持续 1 到 200 毫秒(这是一个“峰值”)。再一次,案例索引的这种变化似乎不是新重建的。

无论如何 - 似乎(目前)问题出在应用程序的 SQL Server 端,因为占用时间的主要是 SNIReadSync 方法。如果我完全无知,请纠正我。

【问题讨论】:

  • 它一定是您在第二个查询中使用表上的主键索引的循环...哦等等,这是一个猜测,因为我看不到您的代码或数据库结构。
  • 使用非顺序 GUID 可能会损害插入性能,但这不应该发生,除非表非常大(> 100 万条记录作为猜测,可能更少)。
  • @MarkSchultheiss 你真的读过这个问题吗?你想看什么代码?反映ObjectContext.SaveChages()?因为那是一条很慢的线路(根据它周围的秒表)。发布整个数据库结构也很成问题,因为它非常复杂(想象一下 10-15 个表,它们之间存在各种可能的关系)。有什么特别需要知道的吗?查看最后两个项目符号 - 这是我问题的奇怪部分。为什么 SaveChanges() 执行时间会随着数据库大小的增加而增加?
  • @leppie 是的,我猜使用 Guid 应该不会影响执行时间。
  • 我的意思是,这实际上是一个性能练习,只有您才能完全了解您的系统以及存在性能瓶颈的地方 - 例如,是否有一些表只需要索引 - 将系统分解并然后在你系统的每个口袋上做一个发现——我不是故意用轻率的评论来侮辱,只是为了指出我在这里所说的。在发生这种情况时运行一些 SQL 性能监控以查看您的需求。

标签: performance sql-server-2008 entity-framework


【解决方案1】:

没有分析器很难猜测,但是 8000 条记录肯定太多了。通常 EF 4 最多可以处理数百个对象。如果更改跟踪花费了大部分时间,我不会感到惊讶。 EF 5 和 6 有一些性能优化,所以如果你不能以某种方式减少被跟踪对象的数量,你可以尝试一下。

【讨论】:

  • 嗯...同样,当数据库为空时,相同数量的更改需要 ±1-2 秒才能执行。数据库增长时只需要这么多时间。这就是我不明白的。尽管您关于使用探查器的观点是有效的 - 这是我仍然需要检查的内容。我虽然可能有人知道数据库大小与调用SaveChanges 所需时间的关系(可能是已知问题或类似问题)。
  • @Jefim 数据库大小与调用SaveChanges 所需时间的关系可能与EF 关系不大,而与数据库的设置方式有关。你的索引是什么?它们是什么类型的索引(集群/非集群)?当涉及到插入时,索引可能会对性能产生一些相当大的影响。您的非空数据库中有多少条记录?
  • 每个表都有一个代理 Guid PK(非聚集索引),所有 FK 也是非聚集索引。当然,我们使用 Guid 的事实意味着索引碎片总是很可怕。该操作中涉及的一张表包含约 400 万行。其他表的行数要少得多(以万计)。并且索引重建后操作性能没有任何改善(当数据库中每个索引的碎片不超过 2-3% 时)。
猜你喜欢
  • 2017-03-23
  • 2018-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多