【发布时间】: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