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

В моем приложении ASP.NET MVC я запускаю несколько вставок одновременно, которые могут вставить 10000 или более строк и обновить несколько других.Этот процесс занимает много времени, но я не могу избежать вставки, потому что это именно то, что мне было предложено сделать.Сейчас я запускаю Sql Server Profiler, и для вставки этой группы строк требуется почти 20 минут.Как я мог улучшить производительность этого действия?

(я использую Linq-to-Sql для вставки данных в базу данных.)

Это код метода, выполняющеговставки:

   [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult SaveEvent(int id)
        {
            int eventID= 0;
            var query = from q in context.InventoryGoods
                        where q.ParentId == id && q.Action.HasValue && q.ActionOn.HasValue == false
                        select q;

            var stockType = from q in context.Inventory
                            where q.Id == id
                            select q.StockType;

            if (query.Count() > 0)
            {
                foreach (var i in query)
                {
                        switch (i.Action.Value)
                        {
                            case (int)InventoryGoodsActionEnum.AdjustLocation:

                                Guid guid = Guid.NewGuid();

                                using (var scope = new TransactionScope())
                                {
                                    GoodsEvent ge = new GoodsEvent()
                                    {
                                        Gid = i.Gid,
                                        Guid = guid,
                                        CreatedOn = DateTime.Now,
                                        EventOn = DateTime.Now,
                                        Type = "LO",
                                        Lid = i.LidObtained,
                                        Comments = "Inventário "+i.ParentId,
                                        UserId = GetUserId(),
                                    };

                                    context.GoodsEvent.InsertOnSubmit(ge);

                                    context.SubmitChanges();
                                    eventID = ge.Id;
                                    Repository.SetActionOn(i.Id, eventID);

                                    scope.Complete();
                                }



                                break;

                            case (int)InventoryGoodsActionEnum.AdjustQuantity:

                                if (!i.QuantityObtained.HasValue)
                                {
                                    guid = Guid.NewGuid();

                                    using (var scope = new TransactionScope())
                                    {
                                        GoodsEvent ge = new GoodsEvent()
                                        {
                                            Gid = i.Gid,
                                            Guid = guid,
                                            CreatedOn = DateTime.Now,
                                            EventOn = DateTime.Now,
                                            Type = "AQ",
                                            Quantity = (short)(i.QuantityExpected * -1),
                                            Comments = "Inventário " + i.ParentId,
                                            UserId = GetUserId(),
                                        };

                                        context.GoodsEvent.InsertOnSubmit(ge);

                                        context.SubmitChanges();
                                        eventID = ge.Id;
                                        Repository.SetActionOn(i.Id, eventID);

                                        scope.Complete();
                                    }

                                }
                                else if ((i.QuantityObtained - (i.QuantityExpected.HasValue ? i.QuantityExpected : 0) != 0))
                                {
                                    guid = Guid.NewGuid();

                                    using (var scope = new TransactionScope())
                                    {
                                        GoodsEvent ge = new GoodsEvent()
                                        {
                                            Gid = i.Gid,
                                            Guid = guid,
                                            CreatedOn = DateTime.Now,
                                            EventOn = DateTime.Now,
                                            Type = "AQ",
                                            Quantity = (short)(i.QuantityObtained.Value - (i.QuantityExpected.HasValue ? i.QuantityExpected : 0)),
                                            Comments = "Inventário " + i.ParentId,
                                            UserId = GetUserId(),
                                        };

                                        context.GoodsEvent.InsertOnSubmit(ge);

                                        context.SubmitChanges();
                                        eventID = ge.Id;
                                        Repository.SetActionOn(i.Id, eventID);

                                        scope.Complete();
                                    }
                                }


                                break;

                            case (int)InventoryGoodsActionEnum.AdjustQuantityLocation:

                                guid = Guid.NewGuid();

                                using (var scope = new TransactionScope())
                                {
                                    GoodsEvent ge = new GoodsEvent()
                                    {
                                        Gid = i.Gid,
                                        Guid = guid,
                                        CreatedOn = DateTime.Now,
                                        EventOn = DateTime.Now,
                                        Type = "LO",
                                        Lid = i.LidExpected,
                                        Comments = "Inventário " + i.ParentId,
                                        UserId = GetUserId(),
                                    };

                                    context.GoodsEvent.InsertOnSubmit(ge);

                                    context.SubmitChanges();
                                    eventID = ge.Id;
                                    Repository.SetActionOn(i.Id, eventID);

                                    scope.Complete();
                                }
                                if (!i.QuantityObtained.HasValue)
                                {
                                    guid = Guid.NewGuid();

                                    using (var scope = new TransactionScope())
                                    {
                                        GoodsEvent ge = new GoodsEvent()
                                        {
                                            Gid = i.Gid,
                                            Guid = guid,
                                            CreatedOn = DateTime.Now.AddSeconds(1),
                                            EventOn = DateTime.Now.AddSeconds(1),
                                            Type = "AQ",
                                            Quantity = (short)(i.QuantityExpected * -1),
                                            Comments = "Inventário " + i.ParentId,
                                            UserId = GetUserId(),
                                        };

                                        context.GoodsEvent.InsertOnSubmit(ge);

                                        context.SubmitChanges();
                                        eventID = ge.Id;
                                        Repository.SetActionOn(i.Id, eventID);

                                        scope.Complete();
                                    }

                                }
                                else if ((i.QuantityObtained - (i.QuantityExpected.HasValue ? i.QuantityExpected : 0) != 0))
                                {
                                    guid = Guid.NewGuid();

                                    using (var scope = new TransactionScope())
                                    {
                                        GoodsEvent ge = new GoodsEvent()
                                        {
                                            Gid = i.Gid,
                                            Guid = guid,
                                            CreatedOn = DateTime.Now.AddSeconds(1),
                                            EventOn = DateTime.Now.AddSeconds(1),
                                            Type = "AQ",
                                            Quantity = (short)(i.QuantityObtained.Value - (i.QuantityExpected.HasValue ? i.QuantityExpected : 0)),
                                            Comments = "Inventário " + i.ParentId,
                                            UserId = GetUserId(),
                                        };

                                        context.GoodsEvent.InsertOnSubmit(ge);

                                        context.SubmitChanges();
                                        eventID = ge.Id;
                                        Repository.SetActionOn(i.Id, eventID);

                                        scope.Complete();
                                    }
                                }



                                break;

                            case (int)InventoryGoodsActionEnum.AdjustStockType:

                                guid = Guid.NewGuid();

                                using (var scope = new TransactionScope())
                                {
                                    GoodsEvent ge = new GoodsEvent()
                                    {
                                        Gid = i.Gid,
                                        Guid = guid,
                                        CreatedOn = DateTime.Now,
                                        EventOn = DateTime.Now,
                                        Type = "ST",
                                        StockType = stockType.First().Value,
                                        Comments = "Inventário " + i.ParentId,
                                        UserId = GetUserId(),
                                    };

                                    context.GoodsEvent.InsertOnSubmit(ge);

                                    context.SubmitChanges();
                                    eventID = ge.Id;
                                    Repository.SetActionOn(i.Id, eventID);

                                    scope.Complete();
                                }


                                break;
                            case (int)InventoryGoodsActionEnum.AdjustLocationStockType:

                                guid = Guid.NewGuid();

                                using (var scope = new TransactionScope())
                                {
                                    GoodsEvent ge = new GoodsEvent()
                                    {
                                        Gid = i.Gid,
                                        Guid = guid,
                                        CreatedOn = DateTime.Now,
                                        EventOn = DateTime.Now,
                                        Type = "ST",
                                        StockType = stockType.First().Value,
                                        Comments = "Inventário " + i.ParentId,
                                        UserId = GetUserId(),
                                    };

                                    context.GoodsEvent.InsertOnSubmit(ge);

                                    context.SubmitChanges();
                                    eventID = ge.Id;
                                    Repository.SetActionOn(i.Id, eventID);

                                    scope.Complete();
                                }

                                 guid = Guid.NewGuid();

                                using (var scope = new TransactionScope())
                                {
                                    GoodsEvent ge = new GoodsEvent()
                                    {
                                        Gid = i.Gid,
                                        Guid = guid,
                                        CreatedOn = DateTime.Now.AddSeconds(1),
                                        EventOn = DateTime.Now.AddSeconds(1),
                                        Type = "LO",
                                        Lid = i.LidExpected,
                                        Comments = "Inventário " + i.ParentId,
                                        UserId = GetUserId(),
                                    };



                                    context.GoodsEvent.InsertOnSubmit(ge);

                                    context.SubmitChanges();
                                    eventID = ge.Id;
                                    Repository.SetActionOn(i.Id, eventID);

                                    scope.Complete();
                                }



                                break;
                            case (int)InventoryGoodsActionEnum.AdjustQuantityStockType:

                                guid = Guid.NewGuid();

                                using (var scope = new TransactionScope())
                                {
                                    GoodsEvent ge = new GoodsEvent()
                                    {
                                        Gid = i.Gid,
                                        Guid = guid,
                                        CreatedOn = DateTime.Now,
                                        EventOn = DateTime.Now,
                                        Type = "ST",
                                        StockType = stockType.First().Value,
                                        Comments = "Inventário " + i.ParentId,
                                        UserId = GetUserId(),
                                    };

                                    context.GoodsEvent.InsertOnSubmit(ge);

                                    context.SubmitChanges();
                                    eventID = ge.Id;
                                    Repository.SetActionOn(i.Id, eventID);

                                    scope.Complete();
                                }

                                if (!i.QuantityObtained.HasValue)
                                {
                                    guid = Guid.NewGuid();

                                    using (var scope = new TransactionScope())
                                    {
                                        GoodsEvent ge = new GoodsEvent()
                                        {
                                            Gid = i.Gid,
                                            Guid = guid,
                                            CreatedOn = DateTime.Now.AddSeconds(1),
                                            EventOn = DateTime.Now.AddSeconds(1),
                                            Type = "AQ",
                                            Quantity = (short)(i.QuantityExpected * -1),
                                            Comments = "Inventário " + i.ParentId,
                                            UserId = GetUserId(),
                                        };

                                        context.GoodsEvent.InsertOnSubmit(ge);

                                        context.SubmitChanges();
                                        eventID = ge.Id;
                                        Repository.SetActionOn(i.Id, eventID);

                                        scope.Complete();
                                    }

                                }
                                else if ((i.QuantityObtained - i.QuantityExpected != 0))
                                {
                                    guid = Guid.NewGuid();

                                    using (var scope = new TransactionScope())
                                    {
                                        GoodsEvent ge = new GoodsEvent()
                                        {
                                            Gid = i.Gid,
                                            Guid = guid,
                                            CreatedOn = DateTime.Now.AddSeconds(1),
                                            EventOn = DateTime.Now.AddSeconds(1),
                                            Type = "AQ",
                                            Quantity = (short)(i.QuantityObtained.Value - i.QuantityExpected),
                                            Comments = "Inventário " + i.ParentId,
                                            UserId = GetUserId(),
                                        };

                                        context.GoodsEvent.InsertOnSubmit(ge);

                                        context.SubmitChanges();
                                        eventID = ge.Id;
                                        Repository.SetActionOn(i.Id, eventID);

                                        scope.Complete();
                                    }
                                }


                                break;
                            case (int)InventoryGoodsActionEnum.AdjustQuantityLocationStockType:

                                guid = Guid.NewGuid();

                                using (var scope = new TransactionScope())
                                {
                                    GoodsEvent ge = new GoodsEvent()
                                    {
                                        Gid = i.Gid,
                                        Guid = guid,
                                        CreatedOn = DateTime.Now,
                                        EventOn = DateTime.Now,
                                        Type = "ST",
                                        StockType = stockType.First().Value,
                                        Comments = "Inventário " + i.ParentId,
                                        UserId = GetUserId(),
                                    };

                                    context.GoodsEvent.InsertOnSubmit(ge);

                                    context.SubmitChanges();
                                    eventID = ge.Id;
                                    Repository.SetActionOn(i.Id, eventID);

                                    scope.Complete();
                                }

                                if (!i.QuantityObtained.HasValue)
                                {
                                    guid = Guid.NewGuid();

                                    using (var scope = new TransactionScope())
                                    {
                                        GoodsEvent ge = new GoodsEvent()
                                        {
                                            Gid = i.Gid,
                                            Guid = guid,
                                            CreatedOn = DateTime.Now.AddSeconds(1),
                                            EventOn = DateTime.Now.AddSeconds(1),
                                            Type = "AQ",
                                            Quantity = (short)(i.QuantityExpected * -1),
                                            Comments = "Inventário " + i.ParentId,
                                            UserId = GetUserId(),
                                        };

                                        context.GoodsEvent.InsertOnSubmit(ge);

                                        context.SubmitChanges();
                                        eventID = ge.Id;
                                        Repository.SetActionOn(i.Id, eventID);

                                        scope.Complete();
                                    }

                                }
                                else if ((i.QuantityObtained - i.QuantityExpected != 0))
                                {
                                    guid = Guid.NewGuid();

                                    using (var scope = new TransactionScope())
                                    {
                                        GoodsEvent ge = new GoodsEvent()
                                        {
                                            Gid = i.Gid,
                                            Guid = guid,
                                            CreatedOn = DateTime.Now.AddSeconds(1),
                                            EventOn = DateTime.Now.AddSeconds(1),
                                            Type = "AQ",
                                            Quantity = (short)(i.QuantityObtained.Value - i.QuantityExpected),
                                            Comments = "Inventário " + i.ParentId,
                                            UserId = GetUserId(),
                                        };

                                        context.GoodsEvent.InsertOnSubmit(ge);

                                        context.SubmitChanges();
                                        eventID = ge.Id;
                                        Repository.SetActionOn(i.Id, eventID);

                                        scope.Complete();
                                    }
                                }

                                 guid = Guid.NewGuid();

                                using (var scope = new TransactionScope())
                                {
                                    GoodsEvent ge = new GoodsEvent()
                                    {
                                        Gid = i.Gid,
                                        Guid = guid,
                                        CreatedOn = DateTime.Now.AddSeconds(2),
                                        EventOn = DateTime.Now.AddSeconds(2),
                                        Type = "LO",
                                        Lid = i.LidExpected,
                                        Comments = "Inventário " + i.ParentId,
                                        UserId = GetUserId(),
                                    };



                                    context.GoodsEvent.InsertOnSubmit(ge);

                                    context.SubmitChanges();
                                    eventID = ge.Id;
                                    Repository.SetActionOn(i.Id, eventID);

                                    scope.Complete();
                                }




                                break;
                    }
                }
            }
            else
            {
                var lista = from q in context.InventoryGoods
                            where q.ParentId == id
                            select q;

                Repository.EvaluateActions(lista.ToList());

                SaveEvent(id);
            }


            using (var scope = new TransactionScope())
            {
                var thisInventory = from i in context.Inventory
                                    where i.Id == id
                                    select i;

                thisInventory.First().State = (int)InventoryStateEnum.Verified;

                context.SubmitChanges();

                scope.Complete();
            }

            Status.Info(string.Format("Acções aplicadas com sucesso."));
            return RedirectToAction("Details", new { id });
        }



 public void SetActionOn(int id, int eventID)
        {
            var InventoryGoods = from i in context.InventoryGoods
                                 where i.Id == id
                                 select i;



            using (var scope = new TransactionScope())
            {
                InventoryGoods.First().ActionOn = DateTime.Now;

                InventoryGoodsEvents ige = new InventoryGoodsEvents
                {
                    EventId = eventID,
                    InventoryGood = InventoryGoods.First().Id,
                };

                context.InventoryGoodsEvents.InsertOnSubmit(ige);

                scope.Complete();
            }
        }

Ответы [ 3 ]

1 голос
/ 21 июля 2010

Linq-to-sql действительно не был предназначен для вставки такого количества записей в базу данных в одном пакете.Это сделает оператор insert оператором insert, что очень медленно.Я бы порекомендовал везде, где вы знаете, вам нужно поддерживать столько вставок, что вы используете объект SqlBulkCopy вместо ваших классов Linq-to-sql.Вы можете даже использовать те же классы L2S, если они вам нужны для проверки объектов, но затем просто сбросьте их в DataTable в 1000 кусочках строк и позвольте SqlBulkCopy сделать ваши фактические вставки.Вы могли бы даже гуглить L2S и SqlBulkCopy и посмотреть, что там есть, до методов расширения или другой интеграции.Вы не первый, кто столкнулся с этой проблемой.

1 голос
/ 21 июля 2010

Прекратите так много использовать var.


Это выполнит запрос дважды (см. В sqlprofiler).

if (query.Count() > 0) 
{ 
  foreach (var i in query) 

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

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

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

foreach(InventoryGood i in rows)
{
  InventoryGoodsEvent ige = new InventoryGoodsEvent()
    //this will attach ige to the object graph tracked by context
    // which is sufficient to insert ige when submitchanges is called.
  ige.InventoryGood = i;

  GoodsEvent ge = GetGoodsEvent(i); //all that conditional logic in there.
    //this will attach ge to the object graph tracked by context
    // which will both insert ge and update ige with ge's id when submitchanges is called.
  ige.GoodsEvent = ge;

  i.ActionOn = DateTime.Now;
    //to submit each row, uncomment this.  
  //context.SubmitChanges();
}
 //to submit all rows at once, use this.
context.SubmitChanges();

Если InventoryGoodEgvents не имеет этих реляционных свойств, зайдите в конструктор и добавьте ассоциации, чтобы создать их.

Как только у вас есть такиекод, то вы можете решить, что нужно сделать за одну транзакцию.Мне нравится вставлять ~ 100 записей за транзакцию.Если вы используете 1 запись на транзакцию, это создает большие накладные расходы на создание каждой транзакции.Если вы используете 1 000 000 строк на транзакцию, это приводит к большим накладным расходам на длительную транзакцию.

Этот материал трудно выучить, но придерживайтесь его.

Еще одна вещь: массовая вставка не являетсяне буду работать с этим столом «многие ко многим».

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

Какой DAL вы используете EF, L2S, ADO.net или что-то еще? Вставка не должна занимать так много времени, чтобы закончить. Вы можете вставить их в локальный кеш и отправить изменения позже.

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