|
05.03.2009, 09:04 | #1 |
Участник
|
Создание большого числа заказов на продажу. Падение скорости загрузки.
Доброго всем дня, уважаемые знатоки, вопрос следущий. Имеется текстовый файл с операциями из другой системы (не Ax), разделитель ";" читаем его используя класс ASCIio, тянем контейнерами построчно.
Данные каждой строки проверяются на правильность. Если проверка пройдена, создатся заказ (если в строке указан новый номер документа) и строка по проверенной строке-контейнеру. Затем в контейнер тянется следующая строчка. Процесс отражается в прогресс баре. Выгладит код по созданию примерно так: X++: //Создание Заказов на продажу static void SalesOrderCreation(Args _args) { SalesTable salesTable; NumberSeq NumberSeq; SalesLine salesLine; InventDim IDim; ; ttsbegin; NumberSeq = NumberSeq::newGetNumFromCode(SalesParameters::numRefSalesId).numberSequence); salesTable.SalesId = NumberSeq.num(); salesTable.initValue(); salesTable.CustAccount = "некий клиент"; salesTable.initFromCustTable(); salesTable.InventLocationId = "некий склад"; salesTable.insert(); //..............строки salesLine.clear(); salesLine.SalesId = salesTable.SalesId; salesLine.ItemId = "некая номенклатура"; IDim.InventColorId ="ххх"; //Измерения IDim.InventLocationId = "ууу"; IDim = InventDim::findOrCreate(IDim); .............................. // Ещё всякое заполнение полей salesLine.InventDimId = IDim.inventDimId; salesLine.createLine(true, true, true, true, false, false, true, false, salesLine.InventTransId); ttscommit; } Проблема же заключается в: В самом начале затяжки файла (120000 операций) процесс идет очень резво - примерно по 300 записей за такт и оставшееся время оценивается 7 минут (по данным прогресс бара). С течением времени первый из показателей плавно снижается, соответственно оцениваемое время растет. На рубеже в 20000 записей данные выглядят так - операций за обновление прогресс бара ориентировочно = 50, а время до завершения = 22 минуты. Становится ясно, что до конца загрузки система не дотянет. От этого становится неимоверно грустно. Как добиться того, что бы показатели скорости обработки не падали? В каком направлении копать? Возможно нужно очищать память или ещё что-нибудь? Подскажите, не оставте без внимания. Заранее благодарен. |
|
05.03.2009, 09:12 | #2 |
Программатор
|
120000 заказов на продажу(судя по джобу), живущих в одной транзакции. А вообще разделите этот файл штук на 5, авось проглотит
|
|
05.03.2009, 09:29 | #3 |
Участник
|
Прошу прощения за корявый код, это примерный джоб с процессом записи, а проблема в рабочем паблик методе . На самом деле в пределах одной транзакции одновременно живет только одна запись. Неважно в STable или SLine.
Разбить-то оно конечно можно, но вот только хочется, что бы скорость не падала. |
|
05.03.2009, 09:21 | #4 |
MCTS
|
Цитата:
static void SalesOrderCreation(Args _args)
Машина там должна быть скореее всего помощнее. Файл, естно, тоже на серваке должен быть. Попутно избавитесь от трафика между клиентом |
|
05.03.2009, 09:34 | #5 |
Программатор
|
паблик метод в студию! А вообще перенесите выполнение кода на сервер. Мож утечка памяти? КР какой? Аксапта какая?
|
|
05.03.2009, 09:49 | #6 |
Участник
|
Да, верно, забыл указать версию. AX 4.0 SP2 международный функционал.
А вот собственно и код. Получаем строку файла в контейнер, проверяем её. Если проверка true, то выполняется след. код. Дальше всё повторяется до самого конца файла. X++: void SalesHeaderCreation(Container _Data_Container) { SalesTable SH; SalesLine SL; InventTable IT; CustTable CT; SalesTableType SalesTableType; Boolean IncreaseLineNo; SalesType SalesType; //Заказ на продажу/Возвраты : 3/4 NumberSeq NumberSeq; InventDim InventDim; SysDim JurFace; InventLocation InventLocation; NumberSequenceCode SeriesNum; NumberSequenceReference NumberSequenceReference; ReturnActionDefaults ReturnActionDefaults; #define.Return("Возврат") #define.Sells("Продажа") #define.KZT("ТНГ") #define.VAT0("НДС0") #define.VATWOUT("БЕЗНДС") #define.VATTRUE("НДС ТРУ") ; // СОЗДАЕМ ЗАГОЛОВОК ДОКУМЕНТА, если предыдущий номер был такой же if (PreviousDocNoSm != conpeek(_Data_Container,3)) { //нужен новый номер документа. ttsbegin; SH.initValue(); NumberSeq = NumberSeq::newGetNum(NumberSeqReference::findReference(typeId2ExtendedTypeId(typeid(SalesId))), true); SH.SalesId = NumberSeq.num(); PreviousDocNoSm = conpeek(_Data_Container,3); PreviousDocNoAx = SH.SalesId; LineNo = 1; //Номер строки в таблице строк SH.SalesType = 3; JurFace = conpeek(_Data_Container,23); SH.CustAccount = conpeek(_Data_Container,5); //Счет клиента SH.initFromCustTable(); SH.SalesStatus = 1; //Открытый заказ if (conpeek(_Data_Container,6)=="да") { SH.InclTax = true; } else { SH.InclTax = false; } SH.CurrencyCode = conpeek(_Data_Container,10); //Валюта if (!SH.CurrencyCode) SH.CurrencyCode = #KZT; //Валюта SH.ShippingDateRequested = str2date(conpeek(_Data_Container,2),123); //Дата отгрузки SH.ReceiptDateRequested = SH.ShippingDateRequested; sh.FixedDueDate = str2date(conpeek(_Data_Container,9),123); SH.DlvMode = strfmt(conpeek(_Data_Container,7)); //Способ оплаты SH.PaymMode = conpeek(_Data_Container,8); //Способ поставки SH.Dimension[1] = JurFace; //Юр Лицо SH.Dimension[5] = 'ДА'; SH.insert(); increaseLineNo = false; ttscommit; } else { increaseLineNo = true; } // СОЗДАЕМ СТРОКИ ДОКУМЕНТА через PreviousDocNo ttsbegin; Select firstfast * from SH where SH.SalesId == PreviousDocNoAx; JurFace = SH.Dimension[1]; SL.clear(); SL.initValue(); SL.SalesId = PreviousDocNoAx; If (IncreaseLineNo) {LineNo+=1;} else {LineNo=1;} SL.LineNum=LineNo; SL.ItemId = conpeek(_Data_Container,11); //Номенклатура Номер Select firstfast * from IT index hint ItemIdx where IT.ItemId == SL.ItemId; SL.initFromSalesTable(SH); SL.initFromCustTable(); InventDim.initValue(); InventDim.inventLocationId = conpeek(_Data_Container,12); InventDim = InventDim::findOrCreate(InventDim); SL.InventDimId = InventDim.inventDimId; switch (conpeek(_Data_Container,20)) { case "0" : SL.TaxItemGroup = #VAT0; break; case "Нет" : SL.TaxItemGroup = #VATWOUT; break; default : //SL.TaxItemGroup = #VATTRUE; break; } SL.LedgerAccount = conpeek(_Data_Container,22); SL.Dimension[1] = SH.Dimension[1]; SL.SalesQty = conpeek(_Data_Container,13); //Количество. if (SL.SalesQty > 0) { SL.QtyOrdered = SL.SalesQty; SL.RemainSalesPhysical = SL.SalesQty; } SL.createLine(true,true,true,true,false,false,true,false,SL.InventTransId); SL.ChangeCreatedDateLine(str2date(conpeek(_Data_Container,2),123)); SL.lineAmount = conpeek(_Data_Container,18); //Чистая сумма ТМЦ select firstfast ReturnActionDefaults; if (conpeek(_Data_Container,1)==#Return) SL.ReturnActionId = ReturnActionDefaults.ReturnActionId; Sl.QtyOrdered = Sl.SalesQty; SL.ReceiptDateRequested = str2date(conpeek(_Data_Container,2),123); SL.ShippingDateRequested = SL.ReceiptDateRequested; SL.update(); ttscommit; } |
|
|
За это сообщение автора поблагодарили: maximka (1). |
05.03.2009, 10:42 | #7 |
Участник
|
Цитата:
Вы бы в условии хотя бы strlwr использовали что-ли... не говоря уже о значениях "Д","Y","Yes", "1". |
|
05.03.2009, 10:47 | #8 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: mazzy (2), petr (2). |
05.03.2009, 09:55 | #9 |
Участник
|
Скорее всего, у вас установлен Recovery model = Full на SQL-сервере.
Это значит, что все транзакции сохраняются до бэкапа. Из-за массовой вставки у вас безумно растет transaction log на SQL-сервере. А поскольку у вас идет постоянное замедление то рискну предположить, что шаг роста слишком маленький и львиную долю времени SQL-сервер тратит не на выполнение транзакций, а на увеличение файла. Если это так, то увеличивайте инкремент для trnasaction log или делайте чаще бэкапы. А еще лучше курите админские доки. Кстати, эффект когда на прогресс-бар показывает постепенное замедление связан с тем, что прогресс-бар использует среднюю оценку - он усредняет быстровыполненные операции с медленно выполняющимися последними. Поскольку медленно выполняющихся становится все больше, то и среднее потихоньку увеличивается, при этом потихоньку увеличивается и оценка оставшегося времени. А на самом деле, скорее всего, с какого-то времени все операции у вас выполняются одинаково медленно Если вы покурили админские доки, но это не помогло, то есть другой момент: Цитата:
Если используете непрерывную, то исправьте код - у вас не хватает вызова метода NumberSeq.used(). Вы не фиксируете факт использования номера, в итоге список незафиксированных номеров у вас растет со старшной силой. |
|
05.03.2009, 10:54 | #10 |
Участник
|
Все верно, Сергей. Модель восстановления - полная. Серия непрерывная. А вот с прогресс баром это интересно.
Я его обновляю после каждой затяжки, каждой из строк. progress.setText(strfmt("Обработано записей: %1", CurrentOperationProgress)); Ясное дело, что обновляется прогресс бар через определенный промежуток времени. Допустим, что каждую секунду. Стало быть такт = 1сек. Так вот в самом начале процесса загрузки число обработываемых строк за такт около 300. Постепенно, при обновлении прогресс бара число обработанных за такт строк снижается. И к пятой-шестой минуте снижается до позорных 50 за такт. Странно. Прошу прощения за следущий вопрос: где увеличить инкремент для trnasaction log? |
|
05.03.2009, 11:07 | #11 |
Участник
|
Цитата:
проверяйте. Цитата:
Сообщение от bobski
Ясное дело, что обновляется прогресс бар через определенный промежуток времени. Допустим, что каждую секунду. Стало быть такт = 1сек. Так вот в самом начале процесса загрузки число обработываемых строк за такт около 300. Постепенно, при обновлении прогресс бара число обработанных за такт строк снижается. И к пятой-шестой минуте снижается до позорных 50 за такт. Странно.
В SQL Server Management Studio |
|
05.03.2009, 10:51 | #12 |
----------------
|
bobski, у вас во внешнем цикле по файлику временная таблица какая-нибудь не используется (покажите джобик)?
|
|
05.03.2009, 12:13 | #13 |
----------------
|
Временная таблица
Видимо, мой вопрос останется без ответа.
Версия При импорте часто используют временные таблицы, в которые сохраняют какие-то промежуточные данные (обычно лог созданного), а при импорте новой строки сверяются с ними, то есть выполняют select. Все прекрасно работает пока временная таблица в ОЗУ, но как только Аксапта скидывает ее на диск начинаются тормоза и чем дальше тем хуже... импорт уходит в бесконечность. Этим страдает и стандартный импорт. Думаю, это ваш случай. |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
05.03.2009, 12:19 | #14 |
Участник
|
Отчего же, Wamr. Ответ есть. Отвлекся. К сожалению временные таблицы не задействованы. Было бы на что грешить, кроме самого себя.
|
|
05.03.2009, 10:59 | #15 |
Программатор
|
Прогреcc бар сделан для пользователей, чтобы имитировать процесс участия. Зачастую показывает всякую хрень.
|
|
05.03.2009, 11:02 | #16 |
Участник
|
а для чего на каждой итерации происходит выборка всей таблицы?
X++: select firstfast ReturnActionDefaults; Последний раз редактировалось ice; 05.03.2009 в 11:05. |
|
05.03.2009, 11:02 | #17 |
MCTS
|
Цитата:
Я его обновляю после каждой затяжки, каждой из строк.
progress.setText(strfmt("Обработано записей: %1", CurrentOperationProgress)); |
|
05.03.2009, 11:11 | #18 |
Участник
|
Цитата:
Прогресс бар дает возможность прервать длительные операции Без него аксапта неохотно принимает даже Ctrl+Break Была ветка про прогесс-бар. Он хорошо написан. И лишнего не делает. Время тратится только на вызов методов. Реальная отрисовка делается только раз в секунду на клиенте или раз в три секунды на сервере (если программист не сказал иного при инициализации). Цитата:
Хотя для отладки можно и так попробовать. |
|
05.03.2009, 11:15 | #19 |
MCITP
|
Цитата:
Попробуйте сделать просто цикл и 120000 вызовов вашего метода, не читая файлик? Что-то изменится? 2. Слишком частый коммит, на самом деле, часто тоже вредит производительности, т.к. при каждом его выполнении серверу БД нужно выполнить т.н. чекпоинт и т.п. Это тема для отдельного разговора, но суть в том, что это дополнительный оверхед. Попробуйте делать коммит хотя бы пачками, по 1000 штук например... Что-то изменится?
__________________
Zhirenkov Vitaly |
|
05.03.2009, 11:36 | #20 |
Участник
|
да, поменяю модель восстановления БД на Простую. Во-вторых сделаю Сжать. Инкремент transaction log поставлю 80 МБ. Транзакции будут закрываться на уровне 1000 записей. Посмотрю на выполнение и скорость снова. Отпишусь.
|
|
Теги |
asciio, createline, заказ, затяжка, скорость |
|
|