2015-08-03 2 views
-5

У меня есть этот код, который выглядит как все контакты и рассчитывается на каждое отправленное им письмо, и если они не открывают/не нажимают последнюю сумму X, а затем возвращают их в спискеЧто я могу сделать для повышения производительности этого кода

В настоящий момент код занимает около 10 минут для запуска, есть ли что-нибудь, что я могу сделать, чтобы улучшить это?

Я знаю, что могу ограничить возвращаемую сумму, но это все еще медленно.

var contactList = 
     (from c in db.Contacts 
      where c.Accounts_CustomerID == Account.AccountID && !c.Deleted && !c.EmailOptOut 
      select c).ToList(); 

    foreach (var person in contactList) 
    { 
     var SentEmails = 
      (from c in db.Comms_Emails_EmailsSents where c.ContactID == person.ID select c).OrderBy(
       x => x.DateSent).Take(Last).ToList(); 

     if (SentEmails.Count == Last) 
     { 
      if (!Clicks) 
      { 
       if (SentEmails.Count(x => x.Opens == 0) == Last) 
       { 
        ReturnContacts.Add(person); 
       } 
      } 
      else 
      { 
       if (SentEmails.Count(x => x.Clicks == 0) == Last) 
       { 
        ReturnContacts.Add(person); 
       } 
      } 
     } 
    } 
    return ReturnContacts; 
+6

Сначала проведите профайлер (например, dotTrace), чтобы просветить ЧТО именно идет медленно. – HimBromBeere

+0

Вам нужен запрос Join. –

ответ

0

Извлеките .ToList() и используйте IQueryables. Используя iqueryables, код будет выполняться один раз и уменьшает объем памяти. ToList() извлекает все сущности и сохраняет их в памяти, которую вы не хотите.

0

Запустить логику на db - переписать запрос с использованием объединений и т. Д., Чтобы он возвращал набор результатов, который уже содержит соответствующие данные.

Что вы делаете сейчас, выполняет запрос db для каждого результата первоначального запроса. Это может означать много запросов.

Если вы выгрузите это на СУРБД, вы всегда можете попробовать и оптимизировать его там (путем введения индексов и т. Д.).

EDIT: Я переписал код в блокноте:

foreach(var record in (from c in db.Contacts 
join es in db.Comms_Emails_EmailsSents 
on c.Id equals es.ContactId 
where c.Accounts_CustomerID == Account.AccountID && !c.Deleted && !c.EmailOptOut 
orderby c.Id, es.DateSent descending 
select new {opens=es.Opens, clicks=es.Clicks, person=c}) 
.GroupBy(r=>r.person)){ 
    var mails = record.Take(Last).ToList(); 
    if(mails.Count == Last){ 
     if(!Clicks){ 
      if(mails.Count(x=>x.opens == 0) == Last){ 
       ReturnContacts.Add(record.Key); 
      } 
     } 
    }else 
      { 
       if (SentEmails.Count(x => x.Clicks == 0) == Last) 
       { 
        ReturnContacts.Add(record.Key); 
       } 
      } 

} 

у меня нет времени на руке, чтобы поиздеваться вверх дб и протестировать его. Кроме того, этот подход выполняет соединение между контактами и электронной почтой, и если у вас есть 100 тыс. Электронных писем на человека, это может быть очень плохой идеей. Вы могли бы оптимизировать его, используя функцию ранга, но я бы сказал, что если производительность все еще плоха, вы можете начать думать о оптимизации db-side, поскольку эта структура данных - по крайней мере, для моих, не-dba глаз - не совсем подходит для такого рода запросов.

+0

Что было бы лучшим способом написать это в sql? используя курсоры? – Samw

+0

Точно НЕ используя курсоры ... если возможно;) Я посмотрю код и попытаюсь обновить свой ответ. – Gerino

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