当属性丢失时,代码优先实体框架变慢

时间:2013-04-02 14:41:00

标签: frameworks ef-code-first entity

我正在使用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行,但它有可能是数百万,所以我绝对不希望在过滤它们之前将所有结果都返回到内存中。

1 个答案:

答案 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();