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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 13.12.2019, 13:36   #1  
kgksoft is offline
kgksoft
Участник
 
37 / 107 (4) +++++
Регистрация: 24.12.2003
Thumbs up AX 2012 R3. Включить OCC на InventSum и выжить
И снова хочу поделиться success-story.
Готовились к черной пятнице и проводили нагрузочные тестирования. Заметили блокировки при большом числе web-вызовов по операциям резервирования по заказам на продажу на InventSum. Нагрузка была такая, что даже номерную серию SalesId пришлось на последовательности в базе MSSQL перевести. Пришла в голову идея таки включить OCC (оптимистические блокировки) на InventSum.

Если посмотреть код на InventUpdateOnhand.ttsNotifyPreCommit, то можно заметить, что COMMIT выполняется логично, но крайне избыточно.
  1. Вставляются новые строки InventSumDelta -> InventSum (причем только ключевые поля без данных). Если строка DELTA-таблицы одна, то строка InventSum даже вставляется (см.п 3)
  2. Блокируются строки InventSum по наличию в InventSumDelta
  3. Далее идет обновление строк InventSum. Тут 2 варианта
    - если строка InventSumDelta была одна, то читаем пессимистически ее и выполняем ей суммирование количеств из InventSumDelta и WRITE (Insert для той самой строки из п.1). Тут без пессимистической блокировки было не обойтись
    - если строк InventSumDelta по нашей транзакции несколько, то ту строится динамический SQL и обновляются строки InventSum на основании группового запроса в InventSumDelta. Тут красиво читаются данные из InventSum и обновление происходит как поле базы += значение из InventSumDelta. InventSum.RecVersion не обновляется. В базе на измененные строки наложена блокировки. Никто не может теперь их читать. Все правильно
  4. Далее дополнительно проводится проверка на отрицательные остатки. И если что-то не так, то идет откат транзакции

Схема красивая рабочая с минимальными блокировками в конце комита, но ... Хочется включить оптимистические блокировки. Если в лоб на таблице InventSum включить OCC, то получаем проблему, когда групповой запрос не обновляет RecVersion, а единичный обновляет измененные строки из-за того, что вычитал старые данные, обновил в памяти кол-во и не упал на обновлении из-за совпадающего RecVersion. Ну и дополнительные выборки с пессимистиком, только чтобы залочить строки перед групповым обновлением.

Чего удалось достичь:
  1. При вставке новых записей InventSumDelta->InventSum вставляются всегда, даже если строка в InventSumDelta одна. Причем вставляются уже с данными для одной строки Delta-таблицы.
    X++:
            if (inventSumDeltaCnt == 1)
            {
                select ItemId, InventDimId,
                    #InventSumDeltaMax
                from inventSumDelta
                    group by ItemId, InventDimId
                    where inventSumDelta.ttsId          == this.ttsId() &&
                          inventSumDelta.IsAggregated   == NoYes::No
                        notexists join inventSum
                        where inventSum.ItemId         == inventSumDelta.ItemId &&
                              inventSum.InventDimId    == inventSumDelta.InventDimId;
            }
  2. Строки вообще не блокируются перед обновлением. По крайней мере при резервировании товара

    X++:
    protected void lockInventSum()
    {
        InventSum           inventSum;
        InventSumDeltaDim   inventSumDeltaDim;
    
        /*
        if (!this.parmDoOnhandCheck()) //!doSummarizedOnhandCheck && !doDirectOnhandCheck && !checkOnHandForWHSItems
        */
        if (!doSummarizedOnhandCheck && !doDirectOnhandCheck)
        {
            return;
        }
  3. При обновлении работает исключительно групповая процедура (прямой SQL) на основании групповой подвыборки InventSumDelta с оптимизациями
    • - для одной строки InventSumDelta, которая была вставлена ранее вызов вообще не выполняется
    • - если строка одна и обновляется, то подвыборка-InventSumDelta не выполняется. Все есть табличной переменной InventSumDelta и в динамический SQL подставляются константы
    • - обновлятся RecVersion в строках InventSum
      RecVersion = ' = FLOOR(RAND()*2147483647)+1'

В итоге блокировки InventSum ушли и подсистема резервирования (по сути любые операции обновления InventSum) стала выдерживать гораздо большие нагрузки от веб-сервисов. Если случаются коллизии при резервировании, когда 2 клиента пытаются одновременно зарезервировать последнюю единицу товара, то транзакция откатится на этапе проверки отрицательных остатков (как было и раньше).
Огромная торговая компания розница + интернет магазин в черную пятницу отлично себя чувствовали при онлайн резервировании.
За это сообщение автора поблагодарили: AlGol (2), Logger (10), gl00mie (15), SRF (7), imir (2).
Теги
inventsum, inventsumdelta, occ

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
emeadaxsupport: BOM Journal postings in AX 2012 R3 vs. earlier versions of AX 2012 Blog bot DAX Blogs 0 03.10.2015 02:35
Dynamics AX Sustained Engineering: Microsoft Dynamics AX 2012 R3 RTM Warehouse Management: How to prevent the creation of two inventDim records considered identical in Dynamics AX 2012 R3 RTM Blog bot DAX Blogs 0 22.12.2014 19:12
emeadaxsupport: AX Performance Troubleshooting Checklist Part 2 Blog bot DAX Blogs 0 09.09.2014 16:11
DAX: Calling all developers: how to ease the learning curve of Microsoft Dynamics AX 2012 R3 Blog bot DAX Blogs 0 27.08.2014 22:11
DAX: Microsoft Dynamics AX 2012 R3 is now available! Blog bot DAX Blogs 1 02.05.2014 23:00

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

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

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