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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 22.07.2011, 18:03   #1  
vallys is offline
vallys
Developer
 
146 / 108 (0) +++++
Регистрация: 18.01.2005
Отмена закрытия склада. Оптимизация.
Здравствуйте!
На форуме подобных исправлений не нашел.

Имеем AX2009 RU5 + MS SQL 2008 R2
Отмена склада идет раз в 10 дольше, чем само закрытие.
Причина: неумелое использование index hint.
Подробности:
В методах \Classes\InventCostClosingCancel_WorkInvent\reverseInventoryAdjustments() и \Classes\InventCostClosingCancel_WorkInvent\duplicateSettlements() в запросах используется index hint DateVoucherIdx, что приводит к Key Lookup (он же Clustered Index Seek с LOOKUP). Данный индекс состоит из полей TransDate, Voucher, RecId. Но в запросах также учавствуют условия по таким полям, как ItemId, InventTransCurrency_RU, Cancelled, SettleModel. Для таких условий целесообразней использовать (из существующих) индекс ItemDateIdx.
Решение:
1. В методах \Classes\InventCostClosingCancel_WorkInvent\reverseInventoryAdjustments() и \Classes\InventCostClosingCancel_WorkInvent\duplicateSettlements() убрать index hint DateVoucherIdx (или поменять на «более подходящий» индекс).
2. В качестве оптимизации, можно добавить в индекс ItemDateIdx поля Voucher, InventTransCurrency_RU, Cancelled, SettleModel, TransRecId.
В результате отмена идет минимум в два раза быстрее самого закрытия (специально не замерял).

Выше упомянутые измененные методы
X++:
/// <summary>
/// Reverses the inventory adjustemts on the inventTrans records made during an inventory closing..
/// </summary>

protected void reverseInventoryAdjustments()
{
    InventTrans         inventTrans;
    InventSettlement    inventSettlement;
    Map                 inventTransMap;
    ;
    inventTransMap = new Map(Types::Int64, Types::Record);

    // First of all, select all the inventTrans records that are necessary
    while select forupdate * from inventTrans
        where inventTrans.ItemId == itemId
        join TableId from inventSettlement
        where inventSettlement.TransRecId             == inventTrans.RecId
           && inventSettlement.ItemId                 == itemId
           && inventSettlement.Voucher                == cancelClosing.Voucher
           && inventSettlement.TransDate              == cancelClosing.TransDate
           // <GEEU>
           && inventSettlement.InventTransCurrency_RU == inventTransCurrency
           // </GEEU>
           && inventSettlement.Cancelled              == NoYes::No
           && inventSettlement.TransRecId             != 0
           && (inventSettlement.SettleModel != InventSettleModel::PhysicalValue
            || (inventSettlement.SettleModel == InventSettleModel::PhysicalValue
             && inventTrans.StatusIssue      == StatusIssue::Deducted))

    {
        inventTransMap.insert(inventTrans.RecId, inventTrans);
    }

    while select sum(QtySettled),sum(CostAmountSettled),sum(CostAmountAdjustment) from inventSettlement
        // VALY, 22.07.2011 -->
        // ускоряем отмену закрытия склада
        // закоментирован код:
        // index hint DateVoucherIdx
        // VALY, 22.07.2011 <--
        group by TransRecId
        where inventSettlement.ItemId                 == itemId
           && inventSettlement.Voucher                == cancelClosing.Voucher
           && inventSettlement.TransDate              == cancelClosing.TransDate
           // <GEEU>
           && inventSettlement.InventTransCurrency_RU == inventTransCurrency
           // </GEEU>
           && inventSettlement.Cancelled              == NoYes::No
           && inventSettlement.TransRecId             != 0
           && inventSettlement.SettleModel            != InventSettleModel::PhysicalValue
    {
        if (inventTransMap.exists(inventSettlement.TransRecId))
        {
            this.updateFinancialCostAmount(inventSettlement, inventTransMap.lookup(inventSettlement.TransRecId));
        }
        else
        {
            this.updateFinancialCostAmount(inventSettlement);
        }
    }

    while select forceplaceholders sum(CostAmountAdjustment) from inventSettlement
        // VALY, 22.07.2011 -->
        // ускоряем отмену закрытия склада
        // закоментирован код:
        // index hint DateVoucherIdx
        // VALY, 22.07.2011 <--
        group by TransRecId
        where inventSettlement.ItemId                 == itemId
           && inventSettlement.Voucher                == cancelClosing.Voucher
           && inventSettlement.TransDate              == cancelClosing.TransDate
           // <GEEU>
           && inventSettlement.InventTransCurrency_RU == inventTransCurrency
           // </GEEU>
           && inventSettlement.Cancelled              == NoYes::No
           && inventSettlement.TransRecId             != 0
           && inventSettlement.SettleModel            == InventSettleModel::PhysicalValue
    exists join inventTrans
        index hint RecId
        where inventTrans.RecId                       == inventSettlement.TransRecId
           && inventTrans.StatusIssue                 == StatusIssue::Deducted
    {
        if (inventTransMap.exists(inventSettlement.TransRecId))
        {
            this.updatePhysicalCostAmount(inventSettlement, inventTransMap.lookup(inventSettlement.TransRecId));
        }
        else
        {
            this.updatePhysicalCostAmount(inventSettlement);
        }
    }
}
X++:
/// <summary>
/// Duplicates the inventsettlement records and marks them as canceled.
/// </summary>

protected void duplicateSettlements()
{
    InventSettlement        cancelSettlenent;
    InventSettlement        inventSettlement;
    InventTrans             inventTrans;
    Voucher                 newVoucher   = inventClosing.Voucher;
    TransDate               newTransDate = inventClosing.TransDate;
    NoYes                   notPosted    = NoYes::No;
    NoYes                   notCanceled  = NoYes::No;

    #LOCALMACRO.InventSettlementFieldsChanged
        TransRecId,
        InventTransId,
        ItemId,
        newTransDate,           // New TransDate
        newVoucher,             // New Voucher
        SettleTransId,
        QtySettled,
        CostAmountSettled,
        CostAmountAdjustment,
        BalanceSheetAccount,
        OperationsAccount,
        notCanceled,            // Canceled = No
        SettleModel,
        Dimension,
        BalanceSheetPosting,
        OperationsPosting,
        ItemGroupId,
        notPosted,              // Posted = No
        SettleType
        // <GEEU>
        ,
        inventTransCurrency,
        MarkupCode_RU
        // </GEEU>
    #ENDMACRO

    ;
    // First of all, duplicate all the settlements not type physical value
    inventSettlement.skipDataMethods(true);
    insert_recordset inventSettlement
        (
        #InventSettlementFields
        )
    select
        #InventSettlementFieldsChanged
    from cancelSettlenent
        // VALY, 22.07.2011 -->
        // ускоряем отмену закрытия склада
        // закоментирован код:
        // index hint DateVoucherIdx
        // VALY, 22.07.2011 <--
        where cancelSettlenent.Voucher                == cancelClosing.Voucher
           && cancelSettlenent.TransDate              == cancelClosing.TransDate
           // <GEEU>
           && cancelSettlenent.InventTransCurrency_RU == inventTransCurrency
           // </GEEU>
           && cancelSettlenent.ItemId                 == itemId
           && cancelSettlenent.Cancelled              == NoYes::No
           && cancelSettlenent.TransRecId             != 0
           && cancelSettlenent.SettleModel            != InventSettleModel::PhysicalValue;

    // Now duplicate all the ones that are physical value and where the transaction is still
    // not financially updated
    // First of all, duplicate all the settlements not type physical value
    inventSettlement.skipDataMethods(true);
    insert_recordset inventSettlement
        (
        #InventSettlementFields
        )
    select
        #InventSettlementFieldsChanged
    from cancelSettlenent
        // VALY, 22.07.2011 -->
        // ускоряем отмену закрытия склада
        // закоментирован код:
        // index hint DateVoucherIdx
        // VALY, 22.07.2011 <--
        where cancelSettlenent.Voucher                == cancelClosing.Voucher
           && cancelSettlenent.TransDate              == cancelClosing.TransDate
           // <GEEU>
           && cancelSettlenent.InventTransCurrency_RU == inventTransCurrency
           // </GEEU>
           && cancelSettlenent.ItemId                 == itemId
           && cancelSettlenent.Cancelled              == NoYes::No
           && cancelSettlenent.TransRecId             != 0
           && cancelSettlenent.SettleModel            == InventSettleModel::PhysicalValue
        exists join inventTrans
            index hint RecId
            where inventTrans.RecId                   == cancelSettlenent.TransRecId   &&
                  inventTrans.StatusIssue             == StatusIssue::Deducted;


    // Now I can update all the records that I have created and reverse the signs
    // Additionally, cancelled will be set to yes, so that this statement does not touch
    // records that have already been reversed
    inventSettlement.skipDataMethods(true);
    update_recordset inventSettlement
        setting Cancelled             = NoYes::Yes,
                QtySettled            = -1 * inventSettlement.QtySettled,
                CostAmountSettled     = -1 * inventSettlement.CostAmountSettled,
                CostAmountAdjustment  = -1 * inventSettlement.CostAmountAdjustment
        where inventSettlement.Voucher                == newVoucher
           && inventSettlement.TransDate              == newTransDate
           // <GEEU>
           && inventSettlement.InventTransCurrency_RU == inventTransCurrency
           // </GEEU>
           && inventSettlement.Cancelled              == NoYes::No
           && inventSettlement.ItemId                 == itemId;

}
P.S. Кстати, статья Сергея Мазуркина про index hint Оптимизация запросов еще не потеряла свою актуальность.

Последний раз редактировалось vallys; 22.07.2011 в 19:50.
За это сообщение автора поблагодарили: Logger (3), alek_frm (1), Dark Light (2), androzavr (1).
Старый 21.06.2012, 15:14   #2  
TravellerInTime is offline
TravellerInTime
Участник
Аватар для TravellerInTime
 
130 / 36 (2) +++
Регистрация: 14.07.2003
Адрес: Россия, Тула
Не особо помогло. Пошёл уже 8й час отмены закрытия.
Закрывался склад где-то с час.
Старый 21.06.2012, 21:59   #3  
online
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Отмена в пакете идет намного быстрее за счет распараллеливания. Попробуйте.
Старый 22.06.2012, 09:37   #4  
TravellerInTime is offline
TravellerInTime
Участник
Аватар для TravellerInTime
 
130 / 36 (2) +++
Регистрация: 14.07.2003
Адрес: Россия, Тула
Цитата:
Сообщение от Logger Посмотреть сообщение
Отмена в пакете идет намного быстрее за счет распараллеливания. Попробуйте.
А чтобы было распараллеливание нужно запускать на выделенном пакетном сервере или можно на клиенте?
Старый 22.06.2012, 10:26   #5  
Vadik is offline
Vadik
Модератор
Аватар для Vadik
Лучший по профессии 2017
Лучший по профессии 2015
 
3,631 / 1849 (69) ++++++++
Регистрация: 18.11.2002
Адрес: гражданин Москвы
Цитата:
Сообщение от TravellerInTime Посмотреть сообщение
А чтобы было распараллеливание нужно запускать на выделенном пакетном сервере или можно на клиенте?
Вы главное версию уточните, а то в 4.0 оно так параллельно (с двух клиентов) отменится - хвостов не найдете. Разъедется InventTrans с InventSum и InventSum с GL
__________________
-ТСЯ или -ТЬСЯ ?
Старый 22.06.2012, 10:53   #6  
TravellerInTime is offline
TravellerInTime
Участник
Аватар для TravellerInTime
 
130 / 36 (2) +++
Регистрация: 14.07.2003
Адрес: Россия, Тула
Цитата:
Сообщение от Vadik Посмотреть сообщение
Вы главное версию уточните
2009RU7 Топик же изначально про 2009ю...
А что значит с двух клиентов - вроде речь про пакетное задание было?
Или отмену склада в 2009 можно запускать с нескольких клиентов одновременно?
Старый 22.06.2012, 11:14   #7  
UNRW is offline
UNRW
Участник
 
383 / 67 (3) ++++
Регистрация: 16.09.2004
Адрес: Москва
помню на 3.0 делал оптимизацию отмены склада...закрывался склад 4 часа, а при откате сеттелмент откатывался за 20 минут, и документ ГК больше часа. Сделали "собственный" способ отмены проводок по ГК: брали оригинальный документ ГК по закрытию и стонировали его. В итоге время отката сократилось в 3 раза
Старый 22.08.2012, 16:45   #8  
Bega is offline
Bega
Участник
Аватар для Bega
 
382 / 444 (15) +++++++
Регистрация: 18.08.2005
Адрес: Москва
DAX2009 SP1 RU8
Коллеги, помогите, чем можете Запустили отмену закрытия, количество помощников 30, отменяется уже несколько дней, прогресс 83% и почти не двигается дальше, куча блокировок, помощники мешают друг другу.

Что посоветуете, как остановить эту отмену? Что будет если убить часть помощников? Какие еще варианты? Если отмена остановится с ошибкой, насколько я понимаю, отката отмены полного не будет? Придется джобами удалять?
Старый 22.08.2012, 17:16   #9  
online
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Можно прервать пакетную обработку принудительно - там кнопка для этого есть.
По идее не должно быть блокировок если вы отменяете только одно закрытие, так как каждый помощник отменяет только пересчет по проводкам одной номенклатуры.
Старый 22.08.2012, 17:23   #10  
Bega is offline
Bega
Участник
Аватар для Bega
 
382 / 444 (15) +++++++
Регистрация: 18.08.2005
Адрес: Москва
Цитата:
Сообщение от Logger Посмотреть сообщение
Можно прервать пакетную обработку принудительно - там кнопка для этого есть.
По идее не должно быть блокировок если вы отменяете только одно закрытие, так как каждый помощник отменяет только пересчет по проводкам одной номенклатуры.
Где именно кнопка? В форме закрытия и коррекции пункт "Приостановить расчет" не работает для отмены.
Помощники мешают друг другу на обновлении таблицы сопоставлений и постоянно возникают dead locks.
Старый 22.08.2012, 17:24   #11  
online
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Еще если не ошибаюсь была бага - в случае когда отменяем много пересчетов, то отмена конкретных InventSettlement шла не в обратном порядке, а как получится. из-за этого могло получиться что в один момент времени 2 разных помощника отменяют складские сопоставления по одной и той же номенклатуре но из разных пересчетов (отсюда и блокировки и конфликты обновления записей с откатом транзакций и даже с выпадением помощников в ошибку).
чтобы такого не было модифицировали немного класс отмены, чтобы он ставил дополнительные зависимости между задачами и отмена шла бы строго в обратной хронологической последовательности,
Старый 22.08.2012, 17:27   #12  
online
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Вот фикс.
Вложения
Тип файла: xpo Class_BatchHeader_2012_08_22_17_26.xpo (100.5 Кб, 286 просмотров)
За это сообщение автора поблагодарили: Bega (5).
Старый 22.08.2012, 17:29   #13  
online
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от Bega Посмотреть сообщение
Где именно кнопка? В форме закрытия и коррекции пункт "Приостановить расчет" не работает для отмены.
Помощники мешают друг другу на обновлении таблицы сопоставлений и постоянно возникают dead locks.
Основное - запросы - Пакетная обработка
Дальше для целого пакета
Функции - Смена статуса
и в ответ выбрать "Отмена"

Аксапта подождет немного и прервет выполнение пакета.
Старый 22.08.2012, 17:40   #14  
Bega is offline
Bega
Участник
Аватар для Bega
 
382 / 444 (15) +++++++
Регистрация: 18.08.2005
Адрес: Москва
Цитата:
Сообщение от Logger Посмотреть сообщение
Основное - запросы - Пакетная обработка
Дальше для целого пакета
Функции - Смена статуса
и в ответ выбрать "Отмена"

Аксапта подождет немного и прервет выполнение пакета.
Она прервет выполнение, но не откатит то, что уже наколбасила, то есть часть номенклатур будет отменена, а часть - нет. Так?
Старый 22.08.2012, 17:43   #15  
Bega is offline
Bega
Участник
Аватар для Bega
 
382 / 444 (15) +++++++
Регистрация: 18.08.2005
Адрес: Москва
Цитата:
Сообщение от Logger Посмотреть сообщение
Еще если не ошибаюсь была бага - в случае когда отменяем много пересчетов, то отмена конкретных InventSettlement шла не в обратном порядке, а как получится. из-за этого могло получиться что в один момент времени 2 разных помощника отменяют складские сопоставления по одной и той же номенклатуре но из разных пересчетов (отсюда и блокировки и конфликты обновления записей с откатом транзакций и даже с выпадением помощников в ошибку).
чтобы такого не было модифицировали немного класс отмены, чтобы он ставил дополнительные зависимости между задачами и отмена шла бы строго в обратной хронологической последовательности,
У нас отменяется только одно закрытие, не очень понимаю, почему они друг другу мешают, видимо эскалация блокировок происходит.
Старый 22.08.2012, 17:53   #16  
fed is offline
fed
Moderator
Аватар для fed
Ex AND Project
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,907 / 5717 (196) ++++++++++
Регистрация: 13.03.2002
Адрес: Hüfingen,DE
1. Можно смело отменить весь BatchJob
2. Затем надо зайти в исходное закрытие (которое отменяешь) и снова щелкнуть кнопочку "Отмена".
Дело в том, что один хелпер отменяет сопоставления по одной номенклатуре и отменяет это в транзакции (так что закрытие по одной номенклатуре либо отменится целиком, либо останется неотмененным). Когда ты снова запускаешь отмену закрытия, оно пробегает по списку inventSettlement неотмененных и генерирует список номенклатур для отмены.

А о причине дидлоков я писал в статье - вторая половина. Лучший способ предотвратить это - построение дополнительных индексов по inventSettlement и prodTableJour
За это сообщение автора поблагодарили: Bega (5), androzavr (1), Logger (3).
Старый 22.08.2012, 17:54   #17  
fed is offline
fed
Moderator
Аватар для fed
Ex AND Project
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,907 / 5717 (196) ++++++++++
Регистрация: 13.03.2002
Адрес: Hüfingen,DE
Кстати - осторожнее с отменой закрытия при средней себестоимости - похоже что там есть баг. Если отменить закрытие, запостить еще приходов или расходов и снова закрыть - результаты будут нехорошими. Например на проводках переноса случиться пересоставление - qtySettled>qty...
За это сообщение автора поблагодарили: Penguin (1), S.Kuskov (1).
Старый 22.08.2012, 18:15   #18  
online
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,940 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от Bega Посмотреть сообщение
Она прервет выполнение, но не откатит то, что уже наколбасила, то есть часть номенклатур будет отменена, а часть - нет. Так?
Да.
Старый 23.08.2012, 08:19   #19  
TravellerInTime is offline
TravellerInTime
Участник
Аватар для TravellerInTime
 
130 / 36 (2) +++
Регистрация: 14.07.2003
Адрес: Россия, Тула
Кстати, я нашел запрос, точнее это оказался апдейт, который вызывал тормоза.
Класс InventCostClosingCancel_WorkInvent метод duplicateSettlements()
X++:
update_recordset inventSettlement
        setting Cancelled             = NoYes::Yes,
                QtySettled            = -1 * inventSettlement.QtySettled,
                CostAmountSettled     = -1 * inventSettlement.CostAmountSettled,
                CostAmountAdjustment  = -1 * inventSettlement.CostAmountAdjustment
        where inventSettlement.Voucher                == newVoucher
           && inventSettlement.TransDate              == newTransDate
           // <GEEU>
           && inventSettlement.InventTransCurrency_RU == inventTransCurrency
           // </GEEU>
           && inventSettlement.Cancelled              == NoYes::No
           && inventSettlement.ItemId                 == itemId;
Анализ показал, что sql server применял не правильный индекс.
Как указать в update_recordset индекс я не нашел, поэтому изменил индекс ItemDateIdx, добавив в него поле Voucher. После этого склад отменяется за минуты вместо часов.
За это сообщение автора поблагодарили: mazzy (2), Bega (5), androzavr (1).
Старый 23.08.2012, 10:34   #20  
vallys is offline
vallys
Developer
 
146 / 108 (0) +++++
Регистрация: 18.01.2005
Цитата:
Сообщение от TravellerInTime Посмотреть сообщение
...
Анализ показал, что sql server применял не правильный индекс.
Как указать в update_recordset индекс я не нашел, поэтому изменил индекс ItemDateIdx, добавив в него поле Voucher. После этого склад отменяется за минуты вместо часов.
Цитата:
Сообщение от vallys Посмотреть сообщение
...
В качестве оптимизации, можно добавить в индекс ItemDateIdx поля Voucher, ...


P.S. Из тех полей что писал в первом сообщении можно и нужно добавлять как раз поле Voucher
Теги
index hint, закрытие склада, отмена закрытия склада

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Ошибка при отмене закрытия склада Geo DAX: Функционал 6 18.02.2011 16:45
Разная себестоимость проводок в операции переноса после закрытия склада Mikky DAX: Функционал 2 27.07.2009 11:52
Отмена закрытия склада, или есть варианты ? CasperSKY DAX: Администрирование 2 12.11.2008 01:11
Отмена закрытия склада. AlexeyBP DAX: Функционал 2 16.01.2008 07:47
Отмена закрытия склада Penguin DAX: Функционал 4 18.05.2005 15:08

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

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

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