AXForum  
Вернуться   AXForum > Блоги > SRF
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

Рейтинг: 5.00. Голосов: 2.

Оптимизация разноски ГК закрытия склада AX2012 R2(российский функционал)

Запись от SRF размещена 17.10.2013 в 23:27

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

Дело в том, что в более ранних версиях еще перед формированием проводок ГК система группировала данные по определенным полям - счетам, типам разноски, аналитикам и т.д.,выполняя суммирование коррекций для последующей разноски. При таком подходе количество "свернутых" строк для разноски в ГК было заметно меньше общего количества строк сопоставления и операция выполнялась сравнительно быстро. В голове крутятся цифры 10-15 минут, вообщем по ощущениям точно не долго.

Достигалось это при помощи следующих двух основных действий - запрос с группировкой по сопоставлениям и дальнейшая группировка данных при помощи map.

Итак, шаг первый - запрос - InventAdjustPostClosing\updateItem (DAX2009)
X++:
    while select forceplaceholders sum(CostAmountAdjustment) from inventSettlement
        index hint DateVoucherIdx
        group by ItemId,ItemGroupId,BalanceSheetPosting,BalanceSheetAccount,OperationsPosting,OperationsAccount,Dimension,TransDate
        where inventSettlement.TransDate                == transDate
           && inventSettlement.Voucher                  == voucher
           /* <SYS>
           && inventSettlement.CostAmountAdjustment     != 0
           </SYS> */
           // <GEEU>
           && ((  flag
           && inventSettlement.CostAmountAdjustment     >  0)
           ||  (! flag
           && inventSettlement.CostAmountAdjustment     <  0))
           && inventSettlement.InventTransCurrency_RU   == this.inventTransCurrency_RU()
           // </GEEU>
           && inventSettlement.Posted                   == NoYes::No
           && inventSettlement.Cancelled                == NoYes::No
    join inventTrans
        index hint recId
        /* <SYS>
        group ProjId,ProjAdjustRefId,InventTransId
        </SYS> */
        // <GEEU>
        group ProjId, ProjAdjustRefId, InventTransId, Storno_RU, StornoPhysical_RU, Direction, StatusReceipt, StatusIssue
        // </GEEU>
        where inventTrans.RecId == inventSettlement.TransRecId
    {
        this.processInventSettlement(inventTrans, inventSettlement);
    }
Здесь в большинстве случаев суммирование идет до номера лота, т.е. не очень сильное "сжатие". Основное происходит на втором шаге при помощи map в методе InventAdjustPost\updateMap_RU(DAX2009)
X++:
    // update map
    cont = [ _inventSettlement.BalanceSheetPosting,
             _inventSettlement.OperationsPosting,
             _inventSettlement.BalanceSheetAccount,
             _inventSettlement.OperationsAccount,
             _inventSettlement.Dimension,
             currencyCode,
             inventModelGroup.StandardCost || inventModelType.stdCostBased(),
             _inventTrans.isUpdatedFinancial() ? _inventTrans.Storno_RU : _inventTrans.StornoPhysical_RU,
             _inventTrans.Direction == InventDirection::Receipt,
             _inventSettlement.CostAmountAdjustment > 0 ];

    if (_inventTrans.ProjId)
    {
        cont += [ _inventTrans.ProjId,
                  _inventTrans.ProjCategoryId,
                  _inventTrans.InventTransId,
                  _inventTrans.ProjAdjustRefId,
                  _inventTrans.ItemId];
    }
Здесь хочется отменить, то что последние 5 параметров выступающих в качестве ключа суммирования, заполняются только в случае, если складская проводка связана с проектом, т.е. для большинства обычных номенклатур произойдет существенное "сжатие", и в результате общее количество свернутых строк для разноски будет заметно меньше общего числа сопоставлений.

Теперь посмотрим, что было сделано в AX2012 R2. Идеология осталась прежней - "сжать" по максимуму до начала процесса разноски ГК, но реализация подкачала.

Действие первое - запрос :

X++:
                while select forceplaceholders sum(CostAmountAdjustment) from inventSettlement
                    index hint DateVoucherIdx
                    group by ItemId,ItemGroupId,
                        BalanceSheetPosting, BalanceSheetLedgerDimension,
                        OperationsPosting, OperationsLedgerDimension,
                        DefaultDimension,TransDate
                    where inventSettlement.TransDate            == transDate
                       && inventSettlement.Voucher              == voucher
                           && ( (processPositiveAdjustment  && inventSettlement.CostAmountAdjustment > 0) ||
                                (!processPositiveAdjustment && inventSettlement.CostAmountAdjustment < 0) )
                       && inventSettlement.Posted               == NoYes::No
                       && inventSettlement.Cancelled            == NoYes::No
                join inventTrans
                    index hint recId
                    group ProjId, ProjAdjustRefId, InventTransOrigin, Storno_RU, StornoPhysical_RU, StatusReceipt, StatusIssue
                    where inventTrans.RecId == inventSettlement.TransRecId
                join Direction from inventTransDirection
                    group by Direction
                    where ((inventTrans.Qty < 0
                        &&   inventTransDirection.Direction      == InventDirection::Issue)
                        ||  (inventTrans.Qty > 0
                        &&   inventTransDirection.Direction      == InventDirection::Receipt))
                {
                    inventTrans.Qty = inventTransDirection.Direction == InventDirection::Receipt ? 1 : -1;
                    this.processInventSettlement(inventTrans, inventSettlement);
                }
Вообщем то, ничего принципиально не изменилось(не считая что отсутствует условие - && inventSettlement.InventTransCurrency_RU == this.inventTransCurrency_RU() - явно мелкий баг, похоже потеряли по дороге), та же группировка по лоту.

Теперь смотрим, что на шаге 2 :
X++:
    inventTransOrigin = _inventTrans.inventTransOrigin();

    // update map
    cont = [ _inventSettlement.BalanceSheetPosting,
             _inventSettlement.OperationsPosting,
             _inventSettlement.BalanceSheetLedgerDimension,
             _inventSettlement.OperationsLedgerDimension,
             _inventSettlement.DefaultDimension,
             currencyCode,
             inventModelGroup.StandardCost || inventModelType.stdCostBased(),
             _inventTrans.isUpdatedFinancial() ? _inventTrans.Storno_RU : _inventTrans.StornoPhysical_RU,
             _inventTrans.Qty > 0,
             _inventSettlement.CostAmountAdjustment > 0,
             _inventTrans.ProjId,
             inventTransOrigin.InventTransId,
             _inventTrans.ProjAdjustRefId];
А вот тут мы видим, что предпоследний элемент ключа суммирования - inventTransOrigin.InventTransId передается всегда - не зависимо от того проводка это по проекту или нет, хотя по факту данный параметр используется только для проектных проводок. В результате "сжатия" не происходит, что приводит к тому, что в разноску передаются все сопоставления один к одному. А это в свою очередь к очень долгому процессу формирования записей в ГК.

В качестве оптимизации шага два предлагается следующий код(замена inventTransOrigin.InventTransId)

X++:
 _inventTrans.ProjId ? inventTransOrigin.InventTransId : '',
В качестве оптимизации шага один предлагается альтернативный запрос, который уже сделает группировку до необходимых параметров(с лотом для проектов, без лота для других номенклатур).

Основа запроса была взята из международной версии(почему так не сделали при локализации вопрос). В стандарте AX2012 R2 была добавлена замечательная возможность добавления вычисляемых полей во View, подробнее msdn. С помощью данной функциональности в международной версии был реализован view - InventAdjustPostInventTransView, вычисляемым полем которого является - projInventTransOrigin - пусто для обычных проводок и projInventTransOrigin = inventTransOrigin для проводок по проектам. С учетом российской специфики, пришлось в данное View добавить еще поле Qty = inventTrans.Qty.

В результате получился вот такой запрос
X++:
                while select forceplaceholders sum(CostAmountAdjustment) from inventSettlement
                    index hint DateVoucherIdx
                    group by ItemId,ItemGroupId,
                        BalanceSheetPosting, BalanceSheetLedgerDimension,
                        OperationsPosting, OperationsLedgerDimension,
                        DefaultDimension,TransDate
                    where inventSettlement.TransDate            == transDate
                       && inventSettlement.Voucher              == voucher
                           && ( (processPositiveAdjustment  && inventSettlement.CostAmountAdjustment > 0) ||
                                (!processPositiveAdjustment && inventSettlement.CostAmountAdjustment < 0) )
                       && inventSettlement.Posted               == NoYes::No
                       && inventSettlement.Cancelled            == NoYes::No
                join inventAdjustPostInventTransView
                    group ProjId, ProjAdjustRefId, ProjInventTransOrigin, Storno_RU, StornoPhysical_RU, StatusReceipt, StatusIssue
                    where inventAdjustPostInventTransView.RecId == inventSettlement.TransRecId
                join Direction from inventTransDirection
                    group by Direction
                    where ((inventAdjustPostInventTransView.Qty < 0
                        &&   inventTransDirection.Direction      == InventDirection::Issue)
                        ||  (inventAdjustPostInventTransView.Qty > 0
                        &&   inventTransDirection.Direction      == InventDirection::Receipt))
                {
                    inventTrans     = inventAdjustPostInventTransView.inventTrans();
                    inventTrans.Qty = inventTransDirection.Direction == InventDirection::Receipt ? 1 : -1;
                    this.processInventSettlement(inventTrans, inventSettlement);
                }
Кстати, если построить такой запрос, то изменений шага один не потребуется, т.к. система автоматически будет возвращать пусто для обычных номенклатур.

Аналогичные изменения по запросам при необходимости можно реализовать и для отмены закрытия.

Теперь цифры(правда это по закрытию склада в основной валюте, но код там тот же, модуль проекты не используется)

Количество сопоставлений, которые идут в разноску ~750 000.

На 11 часу разноски в ГК вывалилась какая то ошибка блокировки временной таблицы, использующейся в корреспонденции(лог корреспонденции).

После изменения запроса - разноска составила 2.5 часа, значение пока устраивает.

И еще небольшой совет - отключите прогресс, для пакетного режима я думаю он никому не нужен.

InventAdjustPost\updateMap_RU
X++:
    if (!Session::isServer()) 
       this.updateProgress_RU(_inventSettlement.ItemId);
Размещено в Без категории
Просмотров 2414 Комментарии 0
Всего комментариев 0

Комментарии

 


Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 19:52.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.