17.05.2006, 12:44 | #1 |
Участник
|
Мертвые блокировки при резерве
Добрый день, всем.
Разбирал недавно код Аксапты - однако много думал :-( Кратко : Есть проблема - возникают мертвые блокировки при резервировании по заказу. В системе создана функция которая в одной транзакции резервирует все строки по заказу. (Функция стартует по кнопке. При работе просто перебирает строчки и для каждой делает резерв. Порядок строк оставлен на усмотрение движка базы данных) Мертвые блокировки возникли на таблице InventSum. Первая догадка - мертвые блокировки возникают потому что при резервировании разных заказов номенклатуры в них перебираются в разном порядке. Например в одном Номенклатура1 затем Номенклатура2 а в это же время в другом заказе в обратном порядке Номенклатура2 затем Номенклатура1 - потенциально это с большой вероятностью приводит к мертвой блокировке в системе. Чтобы этого избежать правильнее было бы везде при переборе строк заказа ставить сортировку по ItemId а также в классах ответственных за резервирование стараться чтобы аналитики перебирались в одном порядке. Теперь, внимание! Самое интересное то, что в таблице SalesLine нет индекса в который бы входили поля SalesId, ItemId (и который был бы полезен для этих целей) Вместо него есть индекс SalesId, LineNum. Кроме того семейство классов SalesFormLetter и SalesTotals используют при переборе строк Query в котором сорировка стоит по LineNum. Например, в SalesFormLetter.updateQueryBuild() стоит chooseLines.query().dataSourceTable(tableNum(SalesLine)).addSortField(fieldNum(SalesLine, salesId)); chooseLines.query().dataSourceTable(tableNum(SalesLine)).addSortField(fieldNum(SalesLine, lineNum)); Таким образом проблема блокировок может возникнуть даже при простой обработке заказа. ( Нам видимо до сих пор везло) Вот я сижу и думаю, почему разработчики аксапты поставили везде сортировки по LineNum. Может какая-то идея хитрая была. Мне вот кажется что для целей производительности лучше везде ставить сортировку по ItemId. Ну и еще для верности по аналитике. Последний раз редактировалось Logger; 17.05.2006 в 13:02. |
|
17.05.2006, 13:24 | #2 |
----------------
|
Простое решение - сделать резервирование по всем строкам с транзакцией только на 1 строчку, а не весь заказ.
|
|
17.05.2006, 14:12 | #3 |
Участник
|
Цитата:
Сообщение от Wamr
Простое решение - сделать резервирование по всем строкам с транзакцией только на 1 строчку, а не весь заказ.
Я тоже хотел для оптимизации сделать резерв по каждой строке в отдельной транзакции. Но по ряду причин требуют чтобы в одной транзакции было резервирование всех строк. Кроме того для случая обработки заказа это не поможет. Там то все строки в одной транзакции обрабатываются - та же проблема будет. (Считаем что система множественных складских транзакций выключена) Я вот никак не пойму, зачем было делать сортировку по LineNum. Пока не вижу от этого никакой пользы. |
|
17.05.2006, 14:33 | #4 |
Участник
|
Хочу уточнить - термин "Мертвые блокировки" - это Deadlock в СУБД или что-то другое имеется ввиду ?
Если это он, то стоит рассказать про Базу и версию. Хинты включены ? Стоить "догадки" про оптимизатор не стоит (там все намного сложнее), просто посмотрите какой индекс пользуется при выполнении запроса. Напишите. подумаю. |
|
17.05.2006, 14:54 | #5 |
Участник
|
Да, это DeadLock
Все хинты выключены. База Оракл. Версия Ax 3.0 sp3 Индекс оптимизатор может выбирать разный в зависимости от условий. я подозреваю, что в случае резервирования он использует SalesLineIdx или SalesStatusIdx Ну в принципе это уже не так важно. Важно понять зачем разработчики навтыкали сортировок по LineNum в SalesFormLetter Последний раз редактировалось Logger; 17.05.2006 в 14:58. |
|
17.05.2006, 15:07 | #6 |
Участник
|
А, ну вот я и пашел себе своей дорогой, раз Оракл ;-)
Сори, тут я некомпетентен. Просто советую к специалистам "заходить" с планом выполнения запроса и статистикой по индексам. Иначе такой народ просто не будет помогать, термины "подозреваю" потусторонни в данном случае. Это из моего опыта тюнинга под Сиквел. Бывают очень даже неожиданные варианты. |
|
17.05.2006, 15:29 | #7 |
Участник
|
Цитата:
Сообщение от Torin
А, ну вот я и пашел себе своей дорогой, раз Оракл ;-)
Сори, тут я некомпетентен. Просто советую к специалистам "заходить" с планом выполнения запроса и статистикой по индексам. Иначе такой народ просто не будет помогать, термины "подозреваю" потусторонни в данном случае. Это из моего опыта тюнинга под Сиквел. Бывают очень даже неожиданные варианты. Torin, мне кажется что вы невнимательно прочитали вопрос. Подобная проблема по идее должна возникать и в SQL2000 Движок базы данных не важен. Если перебор идет по номерам строк, а товары набивались в разном порядке то в заказе 1 номенклатуры могут перебираться так Номенклатура1 затем Номенклатура2 а в заказе 2 : Номенклатура2 затем Номенклатура1 Очевидно что независимо от базы данных при интенсивной работе вероятность мертвой блокировки высока. А если при переборе строк сортировать по ItemId то мертвой блокировки возникнуть не может. Вопрос в том почему в Аксапте стоит сортировка по LineNum. Из соображений оптимизации производительности напрашивается сортировка по ItemId. Последний раз редактировалось Logger; 17.05.2006 в 15:32. |
|
17.05.2006, 15:39 | #8 |
Участник
|
Что-то не понятно.
У вас сначала резервируется заказ1, затем заказ2 в одной транзакции, или резервирование происходит одновременно на разных машинах (в разных копиях Ax)?
__________________
Axapta v.3.0 sp5 kr2 |
|
17.05.2006, 15:48 | #9 |
Участник
|
Цитата:
Сообщение от Logger
Вопрос в том почему в Аксапте стоит сортировка по LineNum. Из соображений оптимизации производительности напрашивается сортировка по ItemId.
|
|
17.05.2006, 16:00 | #10 |
Участник
|
Цитата:
Сообщение от AndyD
Что-то не понятно.
У вас сначала резервируется заказ1, затем заказ2 в одной транзакции, или резервирование происходит одновременно на разных машинах (в разных копиях Ax)? Так что заказ1 с одного рабочего места обрабатывается, а заказ2 с другого одновременно. Вся фишка в том что с разных рабочих мест разные юзеры работают и друг друга блокируют намертво ... Последний раз редактировалось Logger; 17.05.2006 в 16:33. |
|
17.05.2006, 16:07 | #11 |
Участник
|
Цитата:
Сообщение от Logger
Torin, мне кажется что вы невнимательно прочитали вопрос. Подобная проблема по идее должна возникать и в SQL2000
Движок базы данных не важен. Если перебор идет по номерам строк, а товары набивались в разном порядке то в заказе 1 номенклатуры могут перебираться так Номенклатура1 затем Номенклатура2 а в заказе 2 : Номенклатура2 затем Номенклатура1 Очевидно что независимо от базы данных при интенсивной работе вероятность мертвой блокировки высока. А если при переборе строк сортировать по ItemId то мертвой блокировки возникнуть не может. Вопрос в том почему в Аксапте стоит сортировка по LineNum. Из соображений оптимизации производительности напрашивается сортировка по ItemId. 1) Реализация оптимизаторов настолько разная, что лучьше разбираться отдельно, и не держать " в уме" 2) Обход SalesLine по LineNum, кстати, очень логичен ;-) - все транзации движуться в одном направлении. 3) Вопрос в том, каким должен быть обход InventSum - очевидно, совсем другим ;-), как правильно замечено по аналитикам. Тут, конечно, сразу предполагаем, что а) Блокируються и индексы и страницы данных поразному б) Какие индексы, собственно, есть, потому что блокируються все (или нет - зависит от базы) в) Каков план доступа к записи (если неправильный индекс, то дольше транзация и меньше параллелизм) Например, у меня в InventSum есть индекс DATAAREAID (ASC), ITEMID (ASC), INVENTDIMID (ASC) Используется ли он ? Я не знаю. кластерного нет, хинтов нет, значит решает оптимизатор. Какой он выбрал ?. Какие еще индексы заблокируються ? Что именно заблокировано ? Последний, вопрос, кстати, самый важный - на чем дедлок ловиться. Посмотрите - подумаем дальше. |
|
17.05.2006, 16:16 | #12 |
Участник
|
Цитата:
Сообщение от ALES
Из соображений пользовательского интерфейса стоит lineNum, а о производительности "Damgaard" местами совсем не думал..
Для пользователя можно в SalesTable на датасорсе указать индекс SalesLineIdx и она будет строчки по порядку показывать - да так по моему и сделали. А при обработке можно использовать другой индекс. Так что тут программисты не ограничены ничем и исправление делается в два счета. Кроме того я бы не сказал что разработчики аксапты забили на производительность. Судя по коду на это не похоже. Мне кажется что сортировка по LineNum имеет какой то смысл. Ну либо проглючили проггеры. С кем не бывает. |
|
17.05.2006, 16:20 | #13 |
Консультант
|
Вполне логично (с точки зрения пользователя системы) резервирование в порядке строк документа.
|
|
17.05.2006, 16:30 | #14 |
Участник
|
Цитата:
Сообщение от Atar
Вполне логично (с точки зрения пользователя системы) резервирование в порядке строк документа.
|
|
17.05.2006, 16:31 | #15 |
Участник
|
Цитата:
Сообщение от Logger
Почему вы так решили ?
|
|
17.05.2006, 16:36 | #16 |
Модератор
|
Цитата:
Сообщение от Logger
Есть проблема - возникают мертвые блокировки при резервировании по заказу. В системе создана функция которая в одной транзакции резервирует все строки по заказу
Стандартный механизм (Заказ \ Настройки \ Резервирование = Автоматически) у Вас при этом нормально работает ? Если да - ну, Вы поняли..
__________________
-ТСЯ или -ТЬСЯ ? |
|
17.05.2006, 16:45 | #17 |
Участник
|
Цитата:
Сообщение от Vadik
Сколько (в среднем) строк в заказе - десятки, сотни?
Стандартный механизм (Заказ \ Настройки \ Резервирование = Автоматически) у Вас при этом нормально работает ? Если да - ну, Вы поняли.. Авторезервирование не использовали. У нас есть кнопка которую давит юзер и там просто перебираются строчки и для каждой идет резервирование с использованием InventUpd_reservation - все в одной транзакции. Полагаю что случай с авторезервированием был бы легче так как на каждую строчку отдельная транзакция была бы, но его мы применить не можем. Вообще то то эта проблема не всегда возникает а время от времени. Полагаю, просто что в этот момент сервер загружен вот и все. - Запросы медленнее выполняется - вероятность что пересекутся запросы ForUpdate от разных пользователей за один и тот же InventSum - гораздо выше - и пожалуйста принимайте готовенький DeadLock Последний раз редактировалось Logger; 17.05.2006 в 16:48. |
|
17.05.2006, 16:56 | #18 |
злыдень
|
но ведь если все в одной транзакции то какую роль может играть порядок сортировки?
тормозят запросы - их надо оптимизировать, думать не надо )
__________________
Ибо зло есть лучшая сила человека. "Человек должен становиться все лучше и злее" -- так учу я. /Ф. Ницше/ |
|
17.05.2006, 17:23 | #19 |
Участник
|
Цитата:
Сообщение от Recoilme
но ведь если все в одной транзакции то какую роль может играть порядок сортировки?
тормозят запросы - их надо оптимизировать, думать не надо ) Работа с разными строчками идет в одной транзакции, а заказы - в разных обрабатываются с разных рабочих мест, но одновременно Ну смотрите : заказ 1 Строка 1 Номенклатура1 Строка 2 Номенклатура2 заказ 2 Строка 1 Номенклатура2 Строка 2 Номенклатура1 С одного рабочего места начинается транзакция, которая перебирает строки заказа1 обновила строку с номенклатурой1 и на соответсвующей InventSum повесила блокировку, так что другая транзакция не сможет получить её forUpdate ( на чтение прочитает, а forUpdate - фиг) В это же время с другого рабочего места начинается другая транзакция которая обрабатывает заказ 2 обработала в нем строчку номер 1 в которой находится номенклатура 2 и в резульате по номенклатуре 2 повесила блокировку на InventSum, так что никакая другая транзакция не может получить её ForUpdate А дальше первая транзакция пытается получить forUpdate InventSum с номенклатурой 2 - но не может и ждет завершения второй транзакции. а вторая транзакция хочет отобрать forUpdate InventSum с номенклатурой 1 но не может, потому что на ней висит блокировка от первой транзакции. И поэтому вторая транзакция тоже ждет. Вот так они друг друга ждут - классический DeadLock. Он может длиться сколь угодно долго пока БД по таймауту не откатит одну из транзакций. Эта фигня может возникать на сколь угодно можных серверах и сколь угодно оптимизированных запросах. Все дело в порядке перебора записей разными транзакциями. А если мы будем перебирать строки заказа по ItemId то как не трудно заметить мертвой блокировки не получится. Просто одна из транзакций успеет раньше заблокировать Номенклатуру 1 а другая транзакция подождет заверешения её работы вот и все. |
|
17.05.2006, 17:25 | #20 |
Участник
|
Logger, мы не сдвинемся с места, пока не скажете, участников дедлока, что они делали, и на каком уровне дедлок (запись, страница и т.п.). Подозреваю, что Оракл может также сказать на каком объекте и еще массу полезной информации.
|
|