2016-12-07 3 views
0

Мне нужно запросить несколько столбцов из нескольких таблиц с помощью EF. Все идет хорошо и с хорошей производительностью, когда я не включаю отношения M-M в запрос выбора.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 время выполнения записи (мс):

|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 

Почему такое различие (в среднем, медленнее в среднем)? Как повысить производительность запросов?

UPDATE: Отношения между членами и WorkEntity M-M Relationship

UPDATE: Обновлен мой запрос на основе @ AndreFilimon-х внушения:

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: 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? (можете ли вы добавить его?), вы должны избегать запуска этого запроса соединения внутри select, потому что он будет работать в цикле для каждого выбранного элемента. –

+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(); 

нет необходимости использовать Include, потому что вы проецируете в DTO не сущности. DTO не будет обладать свойствами навигации для объектов, которые вы включаете. Include используется для активной загрузки, когда объекты возвращаются.

+0

@kilinger Спасибо за ваш ответ. Я тестировал ваше решение, но у меня было увеличение результатов: 1-е исполнение: 1551 мс, 2-е исполнение: 175 мс, 3-е исполнение: 172. – Ricky

+0

@ Рикки Так я знаю, что искать, какой из них правильный, с или без коллекция? 1-й или второй запрос. – Klinger

+0

правильным является тот, у кого есть коллекция. я должен был внести некоторые изменения, чтобы вернуть правильный результат: 1st: s.MemberWorkEntity.WorkEntity.workEntityLevelID == 2 // 2nd: workEntity = s.MemberWorkEntity.FirstOrDefault (mw => mw.workEntityLevelID = 2 && mw .memberNumber == s.memberNumber) .WorkEntity.name – Ricky

0

Попробуйте переместить включает в себя после того, как, где положение, вы должны получить некоторую общую производительность здесь также: двигаться также внутренний запрос из основного запроса, чтобы избежать присоединяется как ниже:

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-е исполнение: 1478 мс, 2-е исполнение: 147 мс, 3-е исполнение: 122. Что еще я могу попробовать? – Ricky

+0

Опубликуйте модели, чтобы я мог видеть, как они определяются между ними, вам не нужен этот подзапрос, если модели правильно определили свойства навигации. –

+0

я поместил запрос workEntities снаружи и уточнен результат запроса к: (с е в workEntities присоединиться к подкожно в s.MemberWorkEntity на e.workEntityID равна sc.workEntityID выберите e.name) .FirstOrDefault(), но теперь я получите следующую ошибку: «Невозможно создать постоянное значение типа« Domain.Model.WorkEntity ». В этом контексте поддерживаются только примитивные типы или типы перечислений». – Ricky

Смежные вопросы