我正在使用Entity Framework 4.3.1 Code First。
我有一个非常简单的表达式和实体模型。
using (var PMCtx = new PMContext("PMEntities"))
{
var results =
PMCtx.Fetch<vwSDHOriginalMW>()
.Where(x => x.DT >= StartDate && x.DT < EndDate)
.ToList();
return results;
}
public class vwSDHOriginalMW : IEntityObject, IPMContext
{
public int Schedule { get; set; }
public DateTime DT { get; set; }
public int HE { get; set; }
public Decimal OrgMW { get; set; }
public Decimal DELIVERMW { get; set; }
public string NERCCode { get; set; }
public string NERCCodeStatus { get; set; }
public int SDHSDHID { get; set; }
}
每次都需要15秒,而不仅仅是第一次。该模型映射到Sql Server 2008数据库中的视图。我输出了EF正在发送的查询,并在SSMS中运行它只需要几分之一秒。
为什么实体框架中这么慢?
IEntityObject似乎是一个标记接口,因此原始程序员可以确定这些是唯一被放入泛型的。
编辑1 Fetch最终会通过一些图层包装器进入数据层,它会执行此操作:
private DbSet<TEntity> FetchSet<TEntity>()
where TEntity : class, IEntityObject
{
Type PassedType = typeof(TEntity);
if (!CheckedTypes.Any(x => x.FullName == PassedType.FullName))
if (!PassedType.GetInterfaces().Any(x => CtxInterfaces.Contains(x)))
throw new ArgumentException("Type passed is not a DbSet type of constructed context.");
else
CheckedTypes.Add(PassedType);
return privateContext.Set<TEntity>();
}
清理EF正在发送的查询示例
SELECT [Schedule],
[DT],
[HE],
[OrgMW],
[DELIVERMW],
[NERCCode],
[NERCCodeStatus],
[SDHSDHID],
[ScheduleDeliveryHourHistoryID]
FROM [vwSDHOriginalMW]
WHERE ([DT] >= '2/17/2013') AND ([DT] < '2/21/2013')
编辑2 数据库中的视图实际上有一列而不是我的实体模型具有属性。 我将属性添加到模型中。
public class vwSDHOriginalMW : IEntityObject, IPMContext
{
public int Schedule { get; set; }
public DateTime DT { get; set; }
public int HE { get; set; }
public Decimal OrgMW { get; set; }
public Decimal DELIVERMW { get; set; }
public string NERCCode { get; set; }
public string NERCCodeStatus { get; set; }
public int SDHSDHID { get; set; }
//missing property
public int ScheduleDeliveryHourHistoryID { get; set; }
}
昨天加入房产后,它加速了一段时间,在4秒而不是15秒内跑了。但今天它再次变慢,没有任何变化。
更新: 我把它缩小了一点。我可以使用两种方法,最终使用相同的FetchSet。我正在使用的那个返回IQueryable而不是IEnumerable。这似乎是正常的,因为我之后过滤,最令人向往。但是,返回IQueryable的方法需要15秒,而IEnumerable需要不到一秒钟。 (我在两者上调用ToList())FetchAll只是一个调用Fetch的包装器并返回IEnumerable而不是IQueryable
public IQueryable<TEntity> Fetch<TEntity>() where TEntity : class, Common.IEntityObject
{
return privateContext.Fetch<TEntity>();
}
public IEnumerable<TEntity> FetchAll<TEntity>() where TEntity : class, Common.IEntityObject
{
return privateContext.FetchAll<TEntity>();
}
如果我改变
IEnumerable<vwSDHOriginalMW> results =
PMCtx.Fetch<vwSDHOriginalMW>()
.Where(x => x.DT >= StartDate && x.DT < EndDate)
.ToList();
到
IEnumerable<vwSDHOriginalMW> results =
PMCtx.Fetch<vwSDHOriginalMW>()
.ToList()
.Where(x => x.DT >= StartDate && x.DT < EndDate);
它很快。但这是不可接受的,因为我似乎希望将where子句传递给数据库。在这种情况下,在开发环境中,视图只有180行,但它有可能是数百万,所以我绝对不希望在过滤它们之前将所有结果都返回到内存中。
答案 0 :(得分:0)
经过大量挖掘和许多令人头疼的事后,我发现该视图引用了一个不同数据库实例的视图,该实例引用了一个缺少非聚集索引的表。这导致执行计划被错误地缓存。在其他数据库上添加索引后:
USE [OTHERDATABASE]
GO
CREATE NONCLUSTERED INDEX [IX_ScheduleEnergyProfileJoin]
ON [dbo].[WTXS_ScheduleEnergyProfile] ([SEQSDR])
INCLUDE ([SEQSEPI],[StartDate],[EndDate])
GO
然后使用以下视图清除数据库上的执行计划缓存:
USE [MYDATABASE]
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
查询正在快速运行。事实证明,EF说它正在使用的SQL可能不是发送到数据库的sql。故事的道德是我应该通过任何箍来获得对该数据库的分析权限,而不是依赖于以下内容来输出实际发送的SQL。
var sql = ((System.Data.Entity.Infrastructure.DbQuery<vwSDHOriginalMW>)results).ToString();