【发布时间】:2015-10-15 09:53:56
【问题描述】:
在一些用户抱怨速度慢之后,我一直在用探查器查看 WCF 应用程序中的性能瓶颈。
令我惊讶的是,几乎所有问题都归结为实体框架操作。我们使用存储库模式,大多数“添加/修改”代码看起来非常像这样:
public void Thing_Add(Thing thing)
{
Log.Trace("Thing_Add called with ThingID " + thing.ThingID);
if (db.Things.Any(m => m.ThingID == thing.ThingID))
{
db.Entry(thing).State = System.Data.EntityState.Modified;
}
else
{
db.Things.Add(thing);
}
}
这显然是将添加/更新检查包装到单个函数中的便捷方式。
现在,我知道 EF 在进行插入和更新时并不是最有效的方法。但是,我的理解是(一项小研究证实了这一点)它应该能够比用户可能注意到的速度更快地处理数百条记录。
但这对小型 upsert 造成了很大的瓶颈。例如,在一种情况下,处理大约 50 条记录需要 6 秒钟。这是一个特别糟糕的例子,但似乎在整个应用程序中都有一些实例,即小型 EF upsert 需要一两秒以上的时间。肯定足以惹恼用户。
我们将 Entity Framework 5 与 Database First 模型一起使用。探查器说导致问题的不是 Log.Trace。这可能是什么原因造成的,我该如何调查和解决这个问题?
【问题讨论】:
-
6秒在什么环境下?调试?发布?从二进制运行?我问是因为我注意到 EF 在调试时运行异常缓慢,但在编译后的二进制文件中却运行良好。
-
@GrahamBass 已发布。在调试模式下运行速度一样慢。
-
我不知道这是否有帮助,但是如果已经附加了“事物”,则无需将状态设置为已修改。所以如果你在实际上没有改变的事情上调用这个代码,你就是在浪费时间。您可以在将状态设置为已修改之前检查状态是否已分离。
-
另外,您是否在每次调用此方法后调用 SaveChanges()?或者只是一个 SaveChanges() 如果你调用它一次结果会好得多。另外(可能是一个愚蠢的问题)但是数据库中的 ThingId 字段是否有索引/主键?
-
你有 varchar 列吗?我曾多次遇到的一个可能的问题是,如果 where 子句实体框架中有一个 varchar 列,默认情况下将参数化为 nvarchar,从而导致该列显式类型转换为 nvarchar 并忽略索引。 stackoverflow.com/questions/15767803/… 我建议运行 sql profiler 以查看数据库级别的实际情况。
标签: c# entity-framework wcf