Оптимизация разноски ГК закрытия склада AX2012 R2(российский функционал)
Запись от SRF размещена 17.10.2013 в 23:27
Теги ax2012, оптимизация
В локализованной для России версии AX2012 R2 разработчики слегка переписали код разноски сумм коррекций закрытия склада в ГК, причем похоже допустили небольшую ошибку, которая приводит к печальным результатам в плане производительности данной операции.
Дело в том, что в более ранних версиях еще перед формированием проводок ГК система группировала данные по определенным полям - счетам, типам разноски, аналитикам и т.д.,выполняя суммирование коррекций для последующей разноски. При таком подходе количество "свернутых" строк для разноски в ГК было заметно меньше общего количества строк сопоставления и операция выполнялась сравнительно быстро. В голове крутятся цифры 10-15 минут, вообщем по ощущениям точно не долго.
Достигалось это при помощи следующих двух основных действий - запрос с группировкой по сопоставлениям и дальнейшая группировка данных при помощи map.
Итак, шаг первый - запрос - InventAdjustPostClosing\updateItem (DAX2009)
Здесь в большинстве случаев суммирование идет до номера лота, т.е. не очень сильное "сжатие". Основное происходит на втором шаге при помощи map в методе InventAdjustPost\updateMap_RU(DAX2009)
Здесь хочется отменить, то что последние 5 параметров выступающих в качестве ключа суммирования, заполняются только в случае, если складская проводка связана с проектом, т.е. для большинства обычных номенклатур произойдет существенное "сжатие", и в результате общее количество свернутых строк для разноски будет заметно меньше общего числа сопоставлений.
Теперь посмотрим, что было сделано в AX2012 R2. Идеология осталась прежней - "сжать" по максимуму до начала процесса разноски ГК, но реализация подкачала.
Действие первое - запрос :
Вообщем то, ничего принципиально не изменилось(не считая что отсутствует условие - && inventSettlement.InventTransCurrency_RU == this.inventTransCurrency_RU() - явно мелкий баг, похоже потеряли по дороге), та же группировка по лоту.
Теперь смотрим, что на шаге 2 :
А вот тут мы видим, что предпоследний элемент ключа суммирования - inventTransOrigin.InventTransId передается всегда - не зависимо от того проводка это по проекту или нет, хотя по факту данный параметр используется только для проектных проводок. В результате "сжатия" не происходит, что приводит к тому, что в разноску передаются все сопоставления один к одному. А это в свою очередь к очень долгому процессу формирования записей в ГК.
В качестве оптимизации шага два предлагается следующий код(замена inventTransOrigin.InventTransId)
В качестве оптимизации шага один предлагается альтернативный запрос, который уже сделает группировку до необходимых параметров(с лотом для проектов, без лота для других номенклатур).
Основа запроса была взята из международной версии(почему так не сделали при локализации вопрос). В стандарте AX2012 R2 была добавлена замечательная возможность добавления вычисляемых полей во View, подробнее msdn. С помощью данной функциональности в международной версии был реализован view - InventAdjustPostInventTransView, вычисляемым полем которого является - projInventTransOrigin - пусто для обычных проводок и projInventTransOrigin = inventTransOrigin для проводок по проектам. С учетом российской специфики, пришлось в данное View добавить еще поле Qty = inventTrans.Qty.
В результате получился вот такой запрос
Кстати, если построить такой запрос, то изменений шага один не потребуется, т.к. система автоматически будет возвращать пусто для обычных номенклатур.
Аналогичные изменения по запросам при необходимости можно реализовать и для отмены закрытия.
Теперь цифры(правда это по закрытию склада в основной валюте, но код там тот же, модуль проекты не используется)
Количество сопоставлений, которые идут в разноску ~750 000.
На 11 часу разноски в ГК вывалилась какая то ошибка блокировки временной таблицы, использующейся в корреспонденции(лог корреспонденции).
После изменения запроса - разноска составила 2.5 часа, значение пока устраивает.
И еще небольшой совет - отключите прогресс, для пакетного режима я думаю он никому не нужен.
InventAdjustPost\updateMap_RU
Дело в том, что в более ранних версиях еще перед формированием проводок ГК система группировала данные по определенным полям - счетам, типам разноски, аналитикам и т.д.,выполняя суммирование коррекций для последующей разноски. При таком подходе количество "свернутых" строк для разноски в ГК было заметно меньше общего количества строк сопоставления и операция выполнялась сравнительно быстро. В голове крутятся цифры 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); }
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]; }
Теперь посмотрим, что было сделано в 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); }
Теперь смотрим, что на шаге 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)
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);
Всего комментариев 0