Улучшение производительности метода - PullRequest
1 голос
/ 23 июля 2010

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

 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 объектов или более. Итак, где я мог бы немного улучшить его производительность?

Ответы [ 3 ]

0 голосов
/ 23 июля 2010

Это происходит не партиями по 30, а партиями по 1.

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

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

0 голосов
/ 23 июля 2010

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

Попробуйте переместить запросы за пределы цикла следующим образом:

 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 голосов
/ 23 июля 2010

Я не эксперт 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;
    }
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...