设置:
- 启用延迟加载的实体框架 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
方法。如果我完全无知,请纠正我。