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 で実行したところ、ほんの一瞬で完了しました。
Entity Frameworkでこれが遅いのはなぜですか?
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')
EDIT 2 データベースのビューには、実際には、エンティティ モデルにプロパティがあったよりも 1 つ多い列がありました。プロパティをモデルに追加しました。
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; }
}
昨日プロパティを追加した後、しばらくの間、非常に高速になり、15 秒ではなく 4 秒で実行されました。しかし、今日は再び遅くなり、何も変わっていません。
更新: もう少し絞り込みました。同じ FetchSet を使用することになる 2 つの方法があります。私が使用しているものは、IEnumerable ではなく IQueryable を返します。これは正常なようで、後でフィルタリングしているので、最も望ましい. ただし、IQueryable を返すメソッドには 15 秒かかりますが、IEnumerable には 1 秒もかかりません。(両方で ToList() を呼び出しています) FetchAll は、Fetch を呼び出して IQueryable ではなく IEnumerable を返す単なるラッパーであることが判明しました
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 行ですが、数百万になる可能性があるため、フィルタリングする前にすべての結果をメモリに返したくありません。