EntityFramework4.4で発生しているパフォーマンスの問題についてサポートが得られることを期待していました。EDMXファイルを使用していたアプリケーションを最初にコードに変換する作業を行っていますが、LINQクエリの「where」句に多数のオブジェクトを含むクエリを実行すると問題が発生します。
すべてがどのようにレイアウトされているかについての簡単な概要を次に示します(エンティティはEFを参照せず、コード内の一般的な「もの」に付けられた名前です)。
public class ExampleDbContext : DbContext
{
public DbSet<EntityTag> EntityTags { get; set; }
public DbSet<Entity> Entities { get; set; }
public DbSet<Log> Logs { get; set; }
protected override void OnModelCreating(DbmodelBuilder modelBuilder)
{
// Fluent mappings added to modelBuilder.Configurations.Add() in here
}
}
public class EntityTag
{
public int Id { get; set; }
public virtual Entity Entity { get; set; }
public int EntityId { get; set; }
public virtual Log Deleted { get; set; }
public int? DeletedId { get; set; }
}
public class Entity
{
public int Id { get; set; }
pulic byte[] CompositeId { get; set; }
}
// Used to log when an event happens
public class Log
{
public int Id { get; set; }
public string Username { get; set; }
public DateTime Timestamp { get; set; }
}
問題を引き起こす私が実行しているクエリは次のとおりです。
// Creates an IEnumerable<byte[]> with the keys to find
var computedKeys = CreateCompositeIDs(entityKeys);
// Run the query and find any EntityTag that isn't deleted and is in
// the computedKeys list
var result = from et in Context.EntityTags
where computedKeys.Contains(et.Entity.CompositeId) &&
et.Deleted == null
select et;
var entityTags = result.ToList();
計算されたキーに含まれるIDが数個(たとえば15個)の場合、コードとクエリはすばやく実行されます。多数のIDがある場合(この時点では1600は正常であり、さらに高くなる可能性があります)、で列挙されたクエリを実行するのに数分かかります(500では、まだ1500で試していません)ToList()
。computedKeys.Contains()
また、クエリから(et.Deletedを残して)を削除したところcomputedKeys
、クエリがすぐに実行されてしまいました。
デバッグを通じて、キーのリストの作成は高速であると判断したので、それは問題ではありません。プロファイラーをMSSQLに接続して、生成されたクエリを確認すると、すべてのCompositeIdがに含まれているという点で正常に見えますWHERE CompositeId IN ( /* List of Ids, could be 1500 of them */)
。クエリがプロファイラーに表示されると、1秒以内に実行されるため、そうではないと思います。データベースの最適化も。プロファイラーは、すぐに結果を返すときに、最後の1秒程度を除いて、実行中ずっと何も表示されずにそこに座っています。
dotTraceを接続したところ、System.Data.Query.PlanCompiler.JoinGraph.GenerateTransitiveEdge(JoinEdge, JoinEdge)
(119,640 ms)以内に多くの時間が費やされSystem.Collections.Generic.List+Enumerator
ているようで、それぞれの合計実行時間に基づいて、そのメソッド内で1.MoveNext`(54,270 ms)が2回呼び出されたと思います。
クエリの生成に時間がかかる理由がわからないようです。コンパイル後の2回目の実行も高速ではないように思われるため、キャッシュされているようには見えません。
助けてくれてありがとう!