0

我正在使用实体框架 4.3.1 代码优先。

我有一个非常简单的表达式和实体模型。

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 似乎是一个标记接口,因此原始程序员可以确定这些是唯一放入泛型的。

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

4

1 回答 1

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();
于 2013-04-03T13:12:47.307 回答