设定:
Guid.NewGuid()
在代码中生成 - 如果这很重要)SaveChanges
返回的数字大约是8000 - 大多数是添加了对象而另一些是修改过的。)似乎影响此问题的唯一变量是数据库大小。但是请注意,我只是在测量Context.SaveChages()
调用(所以即使我在某个地方有一些不应该影响这个问题的奇怪的缓慢查询)。
对于此操作可能持续这么长时间的任何建议都表示赞赏。
更新1
只是为了澄清 - 执行需要40-60秒的代码是(只有在DB大小约为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 ms(同时仍然给出相同的计数 - 8460)。因此问题是 - 数据库大小如何影响SaveChanges()
?
更新2
运行perf分析器显示主要瓶颈(来自“代码视角”)是以下方法:
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都有非聚集索引。我们使用随机Guids作为代理键(不是顺序),因此碎片总是处于非常高的水平。我尝试在重建所有数据库索引后立即测试执行有问题的操作(所有索引的碎片小于2-3%)但它似乎没有以任何方式改善这种情况。
此外,我必须说,在有问题的操作过程中,该过程中涉及的一个表大约有400万行(该表有很多插入)。 SQL事件探查器显示对该表的插入可以持续1到200毫秒(这是一个“尖峰”)。再一次,在案例索引新近重建的情况下似乎没有这种变化。
在任何情况下 - 似乎(目前)问题出现在应用程序的SQL Server端,因为占用时间的主要因素是SNIReadSync
方法。如果我完全无知,请纠正我。
答案 0 :(得分:0)
没有探查器很难猜测,但8000条记录肯定太多了。通常EF 4可以使用多达几百个对象。如果变化跟踪需要大部分时间,我不会感到惊讶。 EF 5和6有一些性能优化,所以如果你不能以某种方式减少跟踪对象的数量,你可以试验它们。