2010-07-23 2 views
1

Я написал следующий метод, который получает список и обновляет базу данных на основе определенных критериев:Повышение эффективности метода

public void UpdateInventoryGoods(List<InventoryGoods> list, int id) 
     { 
      int index = 0; 

      var query = from inventoryGoods in context.InventoryGoods 
         where inventoryGoods.ParentId == id 
         select inventoryGoods; 

      List<InventoryGoods> goodsList = query.ToList(); 

      using (var scope = new TransactionScope()) 
      { 
       foreach (InventoryGoods i in list) 
       { 
        foreach (InventoryGoods e in goodsList) 
        { 
         if (index == 30) 
         { 
          index = 0; 
          context.SubmitChanges(); 
         } 

         if (e.Gid == i.Gid && !getEventId(e.Id).HasValue && !e.ActionOn.HasValue) 
         { 
          e.Action = i.Action; 

         } 
         else if ((e.Gid == i.Gid && getEventId(e.Id).HasValue) && (e.Action != i.Action || i.ActionOn == DateTime.MinValue)) 
         { 
          e.Action = i.Action; 
          e.ActionOn = null; 

          var allEvents = from invent in context.InventoryGoodsEvents 
              where invent.InventoryGood == e.Id 
              select invent; 

          List<InventoryGoodsEvents> inventoryGoodsEventsList = allEvents.ToList(); 

          var events = from g in context.GoodsEvent           
             select g; 

          List<GoodsEvent> goodsEventList = events.ToList(); 

          foreach (InventoryGoodsEvents goodsEvent in inventoryGoodsEventsList) 
          { 
           context.InventoryGoodsEvents.DeleteOnSubmit(goodsEvent); 

           foreach (GoodsEvent ge in goodsEventList) 
           { 
            if (ge.Id == goodsEvent.EventId) 
            { 
             ge.IsDeleted = true; 
             ge.DeletedOn = DateTime.Now; 
             ge.DeletedBy = System.Web.HttpContext.Current.User.Identity.Name; 
            } 
           }         
          } 




         } 
         ++index; 
        } 
       } 
       context.SubmitChanges(); 
       scope.Complete(); 
      } 

     } 

     public int? getEventId(int InventoryGood) 
     { 


      var InventoryGoodsEvents = from i in context.InventoryGoodsEvents 
             where i.InventoryGood == InventoryGood 
             select i; 

      List<InventoryGoodsEvents> lst = InventoryGoodsEvents.ToList(); 

      if (lst.Count() > 0) 
      { 
       return lst[0].EventId; 
      } 
      else 
      { 
       return null; 
      } 
     } 

Хотя этот метод хорошо работает около 500 или 1000 объектов, она становится слишком медленно или в конце концов, раз когда я кормлю его более 8000 объектов или более. Итак, где я могу улучшить свою производительность?

+0

почему у вас 'context.SubmitChanges()' в 'если (индекс == 30)' состоянии? – fearofawhackplanet

+0

Потому что я представляю его в партиях из 30 записей – Hallaghan

ответ

0

Не вызывайте базу данных в цикле.

Попробуйте переместить запросы вне петли, как это:

public void UpdateInventoryGoods(List<InventoryGoods> list, int id) 
{ 
    int index = 0; 

    var query = from inventoryGoods in context.InventoryGoods 
       where inventoryGoods.ParentId == id 
       select inventoryGoods; 

    List<InventoryGoods> goodsList = query.ToList(); 

    using (var scope = new TransactionScope()) 
    { 
     var allEvents = from invent in context.InventoryGoodsEvents 
         where goodsList.Contains(invent.InventoryGood) 
         select invent; 

     List<InventoryGoodsEvents> inventoryGoodsEventsList = allEvents.ToList(); 

     var events = from g in context.GoodsEvent 
         select g; 

     List<GoodsEvent> goodsEventList = events.ToList(); 

     foreach (InventoryGoods i in list) 
     { 
      foreach (InventoryGoods e in goodsList) 
      { 
       if (index == 30) 
       { 
        index = 0; 
        context.SubmitChanges(); 
       } 

       var eventId = getEventId(e.Id); 
       if (e.Gid == i.Gid && !eventId.HasValue && !e.ActionOn.HasValue) 
       { 
        e.Action = i.Action; 

       } 
       else if ((e.Gid == i.Gid && eventId.HasValue) && (e.Action != i.Action || i.ActionOn == DateTime.MinValue)) 
       { 
        e.Action = i.Action; 
        e.ActionOn = null; 

        foreach (InventoryGoodsEvents goodsEvent in inventoryGoodsEventsList) 
        { 
         context.InventoryGoodsEvents.DeleteOnSubmit(goodsEvent); 

         foreach (GoodsEvent ge in goodsEventList) 
         { 
          if (ge.Id == goodsEvent.EventId) 
          { 
           ge.IsDeleted = true; 
           ge.DeletedOn = DateTime.Now; 
           ge.DeletedBy = System.Web.HttpContext.Current.User.Identity.Name; 
          } 
         } 
        } 
       } 
       ++index; 
      } 
     } 
     context.SubmitChanges(); 
     scope.Complete(); 
    } 
} 
+0

Даже после попыток ваших изменений я не могу ускорить процесс ... это действительно большой объем данных , Можете ли вы мне помочь? – Hallaghan

+0

Я могу попробовать :) По какой причине вы отправляете в партии? – asgerhallas

+0

Потому что он обновляет обычно 8000 или более строк сразу, и это оказывается крайне медленным в приложении браузера. – Hallaghan

0

Я не эксперт Linq, но я думаю, что вы, вероятно, может улучшить getEventId (должен быть капитал первой буквы кстати) с чем-то вроде

public int? GetEventId(int inventoryGood) 
{ 
    var firstInventoryGoodsEvent = context.InventoryGoodsEvents 
        .Where(i => i.InventoryGood == inventoryGood) 
        .FirstOrDefault(); 

    // ...etc 
} 

Использование FirstOrDefault() означает, что вы не обрабатывать весь список если вы найдете соответствующий элемент.

Возможно, существуют другие оптимизации, но довольно сложно следить за тем, что вы делаете. В качестве примера:

foreach (InventoryGoods i in list) 
{ 
    foreach (InventoryGoods e in goodsList) 
    { 
    } 
} 

i и e не придают большого значения здесь. Для вас может быть очевидно, что они означают, но они не очень описательны для тех, кто никогда не видел ваш код раньше. Аналогично, list не является лучшим именем для списка. Список чего? Ваше имя переменной должно описывать ее цель.

Edit:

Я не уверен, что ни о чем другом. Кажется, вы используете ToList() в нескольких местах, где, насколько я вижу, это необязательно. Я не знаю, какое влияние это оказало бы на производительность, но кто-то умнее меня мог бы рассказать вам.

Вы также можете попробовать грузоподъемных некоторые из ваших ценностей за пределами контуров, например:

foreach (foo) 
{ 
    foreach (bar) 
    { 
     DeletedOn = DateTime.Now; 
     DeletedBy = System.Web.HttpContext.Current.User.Identity.Name; 
    } 
} 

может быть переписана в виде

var deletedOn = DateTime.Now; 
var deletedBy = System.Web.HttpContext.Current.User.Identity.Name; 

foreach (foo) 
{ 
    foreach (bar) 
    { 
     DeletedOn = deletedOn; 
     DeletedBy = deletedBy; 
    } 
} 

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

+0

Мне нравится ваше предложение, и если у вас их больше, я бы очень признателен. Прямо сейчас мне нужно как можно больше повысить производительность, потому что он не может дать тайм-ауты у конечного пользователя ... – Hallaghan

+0

i - это то, что я получил от представления (это MVC), а e - это то, что хранится в базе данных.Я сравниваю их друг с другом, чтобы увидеть, что было изменено для обновления. – Hallaghan

+0

Хорошо, спасибо, я рассмотрю все ваши советы и попытаюсь улучшить их дальше. – Hallaghan

0

Это не собирается в партиях от 30, это происходит в партиях от 1

Там в запрос без каких-либо критериев, поэтому она загружает всю таблицу. Это ваше намерение?

getEventId (e.Id) возвращает согласованное значение. Не называть его дважды (за цикл).

+0

Да, это намеренно. Но как это не происходит в партиях из 30? – Hallaghan

+2

Каждая итерация цикла, индекс увеличивается. Обновление не производится на каждой итерации цикла. Фактически, подавляющее большинство итераций цикла не производит никакого обновления (i.Gid == e.Gid) –

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