AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 05.03.2009, 09:04   #1  
bobski is offline
bobski
Участник
 
38 / 11 (1) +
Регистрация: 01.10.2008
Navision Создание большого числа заказов на продажу. Падение скорости загрузки.
Доброго всем дня, уважаемые знатоки, вопрос следущий. Имеется текстовый файл с операциями из другой системы (не 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  
Sada is offline
Sada
Программатор
Аватар для Sada
 
1,450 / 153 (8) ++++++
Регистрация: 29.03.2005
Адрес: Толи Барнаул, толи Москва
120000 заказов на продажу(судя по джобу), живущих в одной транзакции. А вообще разделите этот файл штук на 5, авось проглотит
Старый 05.03.2009, 09:21   #3  
Eldar9x is offline
Eldar9x
MCTS
Аватар для Eldar9x
Oracle
MCBMSS
 
1,064 / 166 (8) ++++++
Регистрация: 29.09.2006
Адрес: Казань
Цитата:
static void SalesOrderCreation(Args _args)
попробуйте плюс к предыдущей идеи от Sada перенести работу полностью на сервер.
Машина там должна быть скореее всего помощнее. Файл, естно, тоже на серваке должен быть.
Попутно избавитесь от трафика между клиентом
Старый 05.03.2009, 09:29   #4  
bobski is offline
bobski
Участник
 
38 / 11 (1) +
Регистрация: 01.10.2008
Прошу прощения за корявый код, это примерный джоб с процессом записи, а проблема в рабочем паблик методе . На самом деле в пределах одной транзакции одновременно живет только одна запись. Неважно в STable или SLine.
Разбить-то оно конечно можно, но вот только хочется, что бы скорость не падала.
Старый 05.03.2009, 09:34   #5  
Sada is offline
Sada
Программатор
Аватар для Sada
 
1,450 / 153 (8) ++++++
Регистрация: 29.03.2005
Адрес: Толи Барнаул, толи Москва
паблик метод в студию! А вообще перенесите выполнение кода на сервер. Мож утечка памяти? КР какой? Аксапта какая?
Старый 05.03.2009, 09:49   #6  
bobski is offline
bobski
Участник
 
38 / 11 (1) +
Регистрация: 01.10.2008
Да, верно, забыл указать версию. 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, 09:55   #7  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Скорее всего, у вас установлен Recovery model = Full на SQL-сервере.
Это значит, что все транзакции сохраняются до бэкапа. Из-за массовой вставки у вас безумно растет transaction log на SQL-сервере. А поскольку у вас идет постоянное замедление то рискну предположить, что шаг роста слишком маленький и львиную долю времени SQL-сервер тратит не на выполнение транзакций, а на увеличение файла.

Если это так, то увеличивайте инкремент для trnasaction log или делайте чаще бэкапы. А еще лучше курите админские доки.

Кстати, эффект когда на прогресс-бар показывает постепенное замедление связан с тем, что прогресс-бар использует среднюю оценку - он усредняет быстровыполненные операции с медленно выполняющимися последними. Поскольку медленно выполняющихся становится все больше, то и среднее потихоньку увеличивается, при этом потихоньку увеличивается и оценка оставшегося времени. А на самом деле, скорее всего, с какого-то времени все операции у вас выполняются одинаково медленно


Если вы покурили админские доки, но это не помогло,
то есть другой момент:
Цитата:
Сообщение от bobski Посмотреть сообщение
X++:
NumberSeq = NumberSeq::newGetNumFromCode(SalesParameters::numRefSalesId).numberSequence);
salesTable.SalesId = NumberSeq.num(); 
...
ttscommit; 
}
Проверьте, не используете ли вы непрерывную номерную серию для заказов.
Если используете непрерывную, то исправьте код - у вас не хватает вызова метода NumberSeq.used().
Вы не фиксируете факт использования номера, в итоге список незафиксированных номеров у вас растет со старшной силой.
__________________
полезное на axForum, github, vk, coub.
Старый 05.03.2009, 10:42   #8  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от bobski Посмотреть сообщение
X++:
void SalesHeaderCreation(Container _Data_Container)
{
...
    if (conpeek(_Data_Container,6)=="да")
...
    SH.Dimension[5] = 'ДА';
}
Охерительно!
Вы бы в условии хотя бы strlwr использовали что-ли...
не говоря уже о значениях "Д","Y","Yes", "1".
__________________
полезное на axForum, github, vk, coub.
Старый 05.03.2009, 10:47   #9  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2925 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
Цитата:
Сообщение от mazzy Посмотреть сообщение
Охерительно!
Вы бы в условии хотя бы strlwr использовали что-ли...
не говоря уже о значениях "Д","Y","Yes", "1".
В аксапте сравнение регистронезависимое. Для регистрозависимого надо использовать strCmp
За это сообщение автора поблагодарили: mazzy (2), petr (2).
Старый 05.03.2009, 10:51   #10  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 858 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
bobski, у вас во внешнем цикле по файлику временная таблица какая-нибудь не используется (покажите джобик)?
Старый 05.03.2009, 10:54   #11  
bobski is offline
bobski
Участник
 
38 / 11 (1) +
Регистрация: 01.10.2008
Все верно, Сергей. Модель восстановления - полная. Серия непрерывная. А вот с прогресс баром это интересно.
Я его обновляю после каждой затяжки, каждой из строк.

progress.setText(strfmt("Обработано записей: %1", CurrentOperationProgress));

Ясное дело, что обновляется прогресс бар через определенный промежуток времени. Допустим, что каждую секунду. Стало быть такт = 1сек. Так вот в самом начале процесса загрузки число обработываемых строк за такт около 300. Постепенно, при обновлении прогресс бара число обработанных за такт строк снижается. И к пятой-шестой минуте снижается до позорных 50 за такт. Странно.

Прошу прощения за следущий вопрос: где увеличить инкремент для trnasaction log?
Старый 05.03.2009, 10:59   #12  
Sada is offline
Sada
Программатор
Аватар для Sada
 
1,450 / 153 (8) ++++++
Регистрация: 29.03.2005
Адрес: Толи Барнаул, толи Москва
Прогреcc бар сделан для пользователей, чтобы имитировать процесс участия. Зачастую показывает всякую хрень.
Старый 05.03.2009, 11:02   #13  
ice is offline
ice
Участник
Аватар для ice
Лучший по профессии 2014
 
1,732 / 406 (17) +++++++
Регистрация: 23.03.2006
а для чего на каждой итерации происходит выборка всей таблицы?
X++:
select firstfast ReturnActionDefaults;
а прогрессбар лучше поменьше обновлять, т.к. он замедляет работу

Последний раз редактировалось ice; 05.03.2009 в 11:05.
Старый 05.03.2009, 11:02   #14  
Eldar9x is offline
Eldar9x
MCTS
Аватар для Eldar9x
Oracle
MCBMSS
 
1,064 / 166 (8) ++++++
Регистрация: 29.09.2006
Адрес: Казань
Цитата:
Я его обновляю после каждой затяжки, каждой из строк.

progress.setText(strfmt("Обработано записей: %1", CurrentOperationProgress));
setText не обязательно обновит текст. Надо использовать progress.update(true) после изменения текста.
Старый 05.03.2009, 11:07   #15  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от belugin Посмотреть сообщение
В аксапте сравнение регистронезависимое. Для регистрозависимого надо использовать strCmp
О! Спасибо, добрый фей. Стало быть я лишний код пишу...

Цитата:
Сообщение от bobski Посмотреть сообщение
Все верно, Сергей. Модель восстановления - полная. Серия непрерывная.
проверяйте.

Цитата:
Сообщение от bobski Посмотреть сообщение
Ясное дело, что обновляется прогресс бар через определенный промежуток времени. Допустим, что каждую секунду. Стало быть такт = 1сек. Так вот в самом начале процесса загрузки число обработываемых строк за такт около 300. Постепенно, при обновлении прогресс бара число обработанных за такт строк снижается. И к пятой-шестой минуте снижается до позорных 50 за такт. Странно.
А дальше снижается или так и остается 50 за такт?


Цитата:
Сообщение от bobski Посмотреть сообщение
Прошу прощения за следущий вопрос: где увеличить инкремент для trnasaction log?
В SQL Server Management Studio
__________________
полезное на axForum, github, vk, coub.
Старый 05.03.2009, 11:11   #16  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Sada Посмотреть сообщение
Прогреcc бар сделан для пользователей, чтобы имитировать процесс участия. Зачастую показывает всякую хрень.
Не...
Прогресс бар дает возможность прервать длительные операции
Без него аксапта неохотно принимает даже Ctrl+Break

Цитата:
Сообщение от ice Посмотреть сообщение
а прогрессбар лучше поменьше обновлять, т.к. он замедляет работу
Была ветка про прогесс-бар.
Он хорошо написан. И лишнего не делает.
Время тратится только на вызов методов. Реальная отрисовка делается только раз в секунду на клиенте или раз в три секунды на сервере (если программист не сказал иного при инициализации).

Цитата:
Сообщение от Eldar9x Посмотреть сообщение
setText не обязательно обновит текст. Надо использовать progress.update(true) после изменения текста.
А вот это точно замедлит работу.
Хотя для отладки можно и так попробовать.
__________________
полезное на axForum, github, vk, coub.
Старый 05.03.2009, 11:15   #17  
ZVV is offline
ZVV
MCITP
MCP
Oracle
MCBMSS
 
1,006 / 246 (11) ++++++
Регистрация: 13.02.2004
Адрес: Минск
->
Цитата:
Сообщение от bobski Посмотреть сообщение
Имеется текстовый файл с операциями из другой системы (не Ax), разделитель ";" читаем его используя класс ASCIio, тянем контейнерами построчно.
1. Может проблема как раз в этом (не уверен)...
Попробуйте сделать просто цикл и 120000 вызовов вашего метода, не читая файлик?
Что-то изменится?

2. Слишком частый коммит, на самом деле, часто тоже вредит производительности, т.к. при каждом его выполнении серверу БД нужно выполнить т.н. чекпоинт и т.п. Это тема для отдельного разговора, но суть в том, что это дополнительный оверхед.
Попробуйте делать коммит хотя бы пачками, по 1000 штук например...
Что-то изменится?
__________________
Zhirenkov Vitaly
Старый 05.03.2009, 11:28   #18  
Eldar9x is offline
Eldar9x
MCTS
Аватар для Eldar9x
Oracle
MCBMSS
 
1,064 / 166 (8) ++++++
Регистрация: 29.09.2006
Адрес: Казань
Цитата:
Попробуйте делать коммит хотя бы пачками, по 1000 штук например...
действительно, я вообще не понимаю зачем создавать для каждой строки транзакцию.
Если у вас там выше (для общего цикла по файлу) нет общей обрамляющей транзакции, тогда в базе будет каша, часть строк создаться, часть нет.
Я бы вообще сделал в виде:

X++:
ttsbegin;
  
{

}
ttscommit;
и все, больше не надо нигде открывать транзакций, тогда гарантировано, либо создадутся все строки по файлу, либо ничего в базе не поменяется.

Цитата:
А вот это точно замедлит работу.
Хотя для отладки можно и так попробовать.
Ну да. Имелось ввиду не для каждой строки. Например, каждые 500 записей.

Последний раз редактировалось Eldar9x; 05.03.2009 в 11:34.
Старый 05.03.2009, 11:36   #19  
bobski is offline
bobski
Участник
 
38 / 11 (1) +
Регистрация: 01.10.2008
да, поменяю модель восстановления БД на Простую. Во-вторых сделаю Сжать. Инкремент transaction log поставлю 80 МБ. Транзакции будут закрываться на уровне 1000 записей. Посмотрю на выполнение и скорость снова. Отпишусь.
Старый 05.03.2009, 11:44   #20  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Eldar9x Посмотреть сообщение
и все, больше не надо нигде открывать транзакций, тогда гарантировано, либо создадутся все строки по файлу, либо ничего в базе не поменяется.
И будет чертовски обидно, если после нескольких часов работы транзакция откатится из-за недостатка места под transaction log
Не говоря уже о тех несчастных пользователях, которые ждут окончания блокировки чтобы продолжить свою никчемную работу по обработке текущих заказов, а также любых складских операций (из-за блокировки inventSum)
__________________
полезное на axForum, github, vk, coub.
Теги
asciio, createline, заказ, затяжка, скорость

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Расчеты с поставщиками\Функции\Создание на основе заказов\Резервирование заказанной номенклатуры slava09 DAX: Функционал 10 30.01.2007 13:57
Создание склад. журналов из заказов basanko DAX: Функционал 17 30.12.2006 11:49
Создание заказов пакетно chel DAX: Администрирование 5 01.07.2004 15:13
"Закупка на основе заказов" или "сводное планирование" Hamster DAX: Функционал 2 17.02.2004 01:47
Создание заказа? 2b4fITin DAX: Функционал 13 02.02.2004 15:52
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 23:01.