2016-12-07 15 views
0

EFを使用して複数のテーブルから複数の列を照会する必要があります。選択クエリにM-M関係を含めないと、すべてうまくいって素晴らしいパフォーマンスが得られます。 MM関係にEntity Framework 6クエリパフォーマンス(M-M関係)

クエリ:

result = (from s in db.Member 
         .Include(i => i.Category) 
         .Include(i => i.MemberWorkEntity) 
         .Include(i => i.Status) 
         .Include(i => i.DiscountMethod) 
         .Where(i => i.C_deleted == null) 
     select new MemberDTO 
     { 
      memberNumber = s.memberNumber, 
      name = s.name, 
      status = s.Status.name, 
      email = s.email, 
      phone = s.phone, 
      mobile = s.mobile, 
      fax = s.fax, 
      workEntity = (from e in db.WorkEntity.Where(i => i.workEntityLevelID == 2) 
         join sc in s.MemberWorkEntity on e.workEntityID equals sc.workEntityID 
         select e.name).FirstOrDefault(), 
      category = s.Category.name, 
      discountMethod = s.DiscountMethod.name, 
      delegate = s.delegate ? "Yes" : "No", 
      leader = s.leader ? "Yes" : "No" 

     }).AsNoTracking().ToList<MemberDTO>(); 

30000レコードの実行時間(ミリ秒):MM関係せず

|1st Execution: 1376 
|2nd Execution: 160 
|3rd Execution: 145 

クエリ:

result = (from s in db.Member 
         .Include(i => i.Category) 
         .Include(i => i.MemberWorkEntity) 
         .Include(i => i.Status) 
         .Include(i => i.DiscountMethod) 
         .Where(i => i.C_deleted == null) 
     select new MemberDTO 
     { 
      memberNumber = s.memberNumber, 
      name = s.name, 
      status = s.Status.name, 
      email = s.email, 
      phone = s.phone, 
      mobile = s.mobile, 
      fax = s.fax, 
      //removed M-M Relationship Query 
      category = s.Category.name, 
      discountMethod = s.DiscountMethod.name, 
      delegate = s.delegate ? "Yes" : "No", 
      leader = s.leader ? "Yes" : "No" 

     }).AsNoTracking().ToList<MemberDTO>(); 

30000レコードの実行時間(ミリ秒) :

|1st Execution: 1286 
|2nd Execution: 79 
|3rd Execution: 67 

なぜこのような違いが(平均2倍遅いのですか)?どのようにしてクエリのパフォーマンスを向上させることができますか?

UPDATE:

IEnumerable<WorkEntity> workEntities = db.WorkEntity.AsNoTracking().Where(i => i.workEntityLevelID == 2); 

result = (from s in db.Member 
         .Include(i => i.Category)       
         .Include(i => i.Status) 
         .Include(i => i.DiscountMethod) 
         .Where(i => i.C_deleted == null) 
     select new MemberDTO 
     { 
      memberNumber = s.memberNumber, 
      name = s.name, 
      status = s.Status.name, 
      email = s.email, 
      phone = s.phone, 
      mobile = s.mobile, 
      fax = s.fax, 
      workEntity = (from e in workEntities 
         join sc in s.MemberWorkEntity on e.workEntityID equals sc.workEntityID 
         select e.name).FirstOrDefault(), 
      category = s.Category.name, 
      discountMethod = s.DiscountMethod.name, 
      delegate = s.delegate ? "Yes" : "No", 
      leader = s.leader ? "Yes" : "No" 

     }).AsNoTracking().ToList<MemberDTO>(); 

30000レコードの実行時間(ミリ秒):

@ AndreFilimonの提案に基づいて、私のクエリを更新:メンバーとWorkEntity M-M Relationship

UPDATEとの関係

|1st Execution: 1364 |2nd Execution: 122 |3rd Execution: 120 

UPDATE:@agfcが示唆したように、私のメンバー表に単純なインデックスを追加しました:

IEnumerable<WorkEntity> workEntities = db.WorkEntity.AsNoTracking().Where(i => i.workEntityLevelID == 2); 

result = (from s in db.Member 
         .Include(i => i.Category)       
         .Include(i => i.Status) 
         .Include(i => i.DiscountMethod) 
         .Where(i => i.C_deleted == null) 
     select new MemberDTO 
     { 
      memberNumber = s.memberNumber, 
      name = s.name, 
      status = s.Status.name, 
      email = s.email, 
      phone = s.phone, 
      mobile = s.mobile, 
      fax = s.fax, 
      workEntity = (from e in workEntities 
         join sc in s.MemberWorkEntity on e.workEntityID equals sc.workEntityID 
         select e.name).FirstOrDefault(), 
      category = s.Category.name, 
      discountMethod = s.DiscountMethod.name, 
      delegate = s.delegate ? "Yes" : "No", 
      leader = s.leader ? "Yes" : "No" 

     }).AsNoTracking().ToList<MemberDTO>(); 

30000レコードの実行時間(ミリ秒):

|1st Execution: 1544 
|2nd Execution: 109 
|3rd Execution: 105 

UPDATE:クリンガーの答え@に基づいて変更クエリ:

result = db.MemberWorkEntity.Where(mw => mw.WorkEntity.workEntityLevelID == 2 && mw.Member.C_deleted == null) 
     .Select(s => new MemberDTO 
     { 
      memberNumber = mw.Member.memberNumber, 
      name = mw.Member.name, 
      status = mw.Member.Status.name, 
      email = mw.Member.email, 
      phone = mw.Member.phone, 
      mobile = mw.Member.mobile, 
      fax = mw.Member.fax, 
      workEntity = mw.WorkEntity.name, 
      category = mw.Member.Category.name, 
      discountMethod = mw.Member.DiscountMethod.name, 
      @delegate = [email protected] ? "Yes" : "No", 
      leader = mw.Member.leader ? "Yes" : "No" 
     }).ToList(); 

30000レコードの実行時間(ミリ秒):

|1st Execution: 1427 
|2nd Execution: 80 
|3rd Execution: 76 
+0

投影内に結合を含むサブクエリが含まれていますが、当然遅くなります – Tuco

+0

Member.MemberWorkEntityとWorkEntityの間の直接のナビゲーションはありませんか? (あなたは1つを追加できますか?)、select内でそのjoinクエリを実行しないでください。これは、選択された各項目のループで実行されるためです。 –

+0

@Tuco自然にそれは遅くなる、私の質問は私がそれがより速くなるために私のクエリにどのような変更を加えることができるかです。 – Ricky

答えて

1

なし: はまた、怒鳴る加入を避けるために、メイン・クエリのうち、内側のクエリを移動あなたのエンティティの正確な形状を見ていない、次のようなものが何をすべき:

result = db.MemberWorkEntity.Where(mw => mw.WorkEntity.workEntityLevelID == 2 && mw.Member.C_deleted == null) 
     .Select(s => new MemberDTO 
{ 
    memberNumber = mw.Member.memberNumber, 
    name = mw.Member.name, 
    status = mw.Member.Status.name, 
    email = mw.Member.email, 
    phone = mw.Member.phone, 
    mobile = mw.Member.mobile, 
    fax = mw.Member.fax, 
    workEntity = mw.WorkEntity.name, 
    category = mw.Member.Category.name, 
    discountMethod = mw.Member.DiscountMethod.name, 
    @delegate = [email protected] ? "Yes" : "No", 
    leader = mw.Member.leader ? "Yes" : "No" 
}).ToList(); 

あなたはDTOないエンティティ内に突出しているのでIncludeを使用する必要はありません。 DTOには、あなたが含むエンティティへのナビゲーションプロパティはありません。 Includeは、エンティティが返されたときに熱心な読み込みに使用されます。

+0

@kilingerあなたの答えに感謝します。私はあなたのソリューションをテストしましたが、私は結果を増やしました:1回目の実行:1551ms、2回目の実行:175ms、3回目の実行:1722. – Ricky

+0

@Rickyちょうど私は何を探すべきかを知っています。コレクション? 1番目または2番目のクエリ。 – Klinger

+0

正しいものがコレクションのものです。私はそれが正しい結果を返すためにいくつかの変更を加えなければならなかった:1:s.MemberWorkEntity.WorkEntity.workEntityLevelID == 2 // 2:workEntity = s.MemberWorkEntity.FirstOrDefault(mw => mw.workEntityLevelID = 2 && mw .memberNumber == s.memberNumber).WorkEntity.name – Ricky

0

where句の後に含まれて移動しようと、あなたはまた、ここでいくつかの全体的なパフォーマンスを得る必要があります。

var workEntities=(from e in db.WorkEntity).Where(e=>e.workEntityLevelID==2).ToList(); 
var result = (from s in db.Member.Where(i => i.C_deleted == null).Include(i => i.Category).Include(i => i.MemberWorkEntity).Include(i => i.Status).Include(i => i.DiscountMethod) 
      select new MemberDTO 
      { 
       memberNumber = s.memberNumber, 
       name = s.name, 
       status = s.Status.name, 
       email = s.email, 
       phone = s.phone, 
       mobile = s.mobile, 
       fax = s.fax, 
       workEntity = workEntities.Where(e=>e.workEntityID ==sc.workEntityID).DefaultIfEmpty().Select(e=>e.name).FirstOrDefault(), 
       category = s.Category.name, 
       discountMethod = s.DiscountMethod.name, 
       delegate = s.delegate ? "Yes" : "No", 
       leader = s.leader ? "Yes" : "No" 

      }).AsNoTracking().ToList<MemberDTO>(); 
+0

私はあなたの提案に基づいてクエリを修正し、パフォーマンスは少し向上しましたが、第1実行:1478ms、第2実行:147ms、第3実行:122。 – Ricky

+0

モデルを投稿して、それらの間でナビゲーションがどのように定義されているかを確認できます。モデルにナビゲーションプロパティが正しく定義されている場合は、サブクエリは必要ありません。 –

+0

私は外workEntitiesクエリを配置し、その結果にクエリを更新: (workEntities にeからe.workEntityIDにs.MemberWorkEntityで皮下に参加sc.workEntityIDがe.nameを選択 等しい).FirstOrDefault()、 しかし、今私「Domain.Model.WorkEntity型の定数値を作成できません。プリミティブ型または列挙型のみがこのコンテキストでサポートされています。」 – Ricky

関連する問題