EF 4.3.1和EF 5.0 DbSet.Local比实际的数据库查询慢

时间:2012-08-31 22:39:02

标签: .net vb.net entity-framework entity-framework-5 entity-framework-4.3.1

我有一个数据库,其中包含大约16,500个城市的表格,以及该数据库的EF数据模型(数据库优先)。我用代码将它们预加载到内存中:

Db.Cities.Load()

...然后在使用它们的时候,我尝试了以下每个查询:

Dim cities() As String = Db.Cities.Select(Function(c) c.CityName).ToArray

Dim cities() As String = Db.Cities.Local.Select(Function(c) c.CityName).ToArray

第一个查询是快速的(约10毫秒),但是第二个查询第一次运行需要大约2.3秒(尽管它比第一个查询在此之后调用时更快)。

这没有意义,因为SQL Server Profiler会验证第一个查询是否正在另一台计算机上访问数据库,但第二个查询不是!

我尝试关闭Db.Configuration.AutoDetectChangesEnabled,我尝试预先生成视图。

如何才能让.Local更快? (并非所有运行此应用程序的客户端都将位于快速LAN上。)

3 个答案:

答案 0 :(得分:9)

我使用Resharper方便的功能走了Local属性的源代码。您首先会看到DetectChanges的来电,如果您正在运行的是以上三行,则可能不是您的问题。但是EF为Local创建了一个新的ObservableCollection并逐项填充。第一次通话中的任何一个都可能成本很高。

直接针对DbSet的查询将路由到EF数据库提供程序,我确信它可以直接访问内部本地缓存。

答案 1 :(得分:6)

以下扩展方法将返回包含DbSet的本地缓存实体的IEnumerable<T>,而不会因检测上下文更改和创建DbSet.Local()对象的ObservableCollection<T>方法而产生启动开销。

<Extension()>
Public Function QuickLocal(Of T As Class)(ByRef DbCollection As DbSet(Of T)) As IEnumerable(Of T)
    Dim baseType = DbCollection.[GetType]().GetGenericArguments(0)
    Dim internalSet = DbCollection.GetType().GetField("_internalSet", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance).GetValue(DbCollection)
    Dim internalContext = internalSet.GetType().GetProperty("InternalContext").GetValue(internalSet, Nothing)
    Return DirectCast(internalContext.GetType.GetMethod("GetLocalEntities").MakeGenericMethod(baseType).Invoke(internalContext, Nothing), IEnumerable(Of T))
End Function

在包含19,679个实体的DbSet上调用.QuickLocal需要9 ms,而在第一次调用时调用.Local需要2121 ms。

答案 2 :(得分:0)

为什么不直接从第一个查询中保存字符串列表并使用它。

List<string> cities = db.Cities.Select( x=>x.CityName).ToList();

由于Select,Local可能会变慢,这可能会进行一些一致性检查。