Добро пожаловать в форум, Guest >> Войти | Регистрация | Поиск | Правила | | В избранное | Подписаться | ||
Все форумы / Microsoft SQL Server |
![]() ![]() |
Artyom E Member Откуда: Сообщений: 2 |
Текст знаменитой ошибки 1205: "Транзакция (с идентификатором процесса %d) вызвала взаимоблокировку ресурсов %.*ls с другим процессом и была выбрана в качестве жертвы для ее разрешения. Запустите транзакцию повторно." В тексте ошибки предлагается перезапустить транзакцию. Почему я должен писать код, отлавливающий это исключение, и перезапускающий транзакцию? Меня давно мучает вопрос, почему для транзакции нельзя задать параметры перезапуска на тот случай, если она стала жертвой взаимоблокировки? Реализовать перехватывание ошибки взаимоблоировки и повторный запуск транзакции - достаточно проблематично и трудоемко. Гораздо проще было бы задать два параметра для транзакции на случай ее отката при дедлоке: количество повторных попыток транзакции, временной интервал между повторами транзакции. Само собой, желательно свести дедлоки к минимуму. Но исключить их полностью не всегда возможно. Почему эта проблема переложена на плечи разработчика? И в СУБД SQL Server не предусмотрены соответствующие настройки для транзакции? |
21 фев 19, 20:16 [21816834] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9683 |
Крик души? Опишите свою хотелку на User Voice, - возможно MS ее когда-нибудь реализует, если наберется достаточно голосов "за". |
21 фев 19, 21:22 [21816867] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31816 |
Хотя, конечно, может, и бывло бы востребовано. Предложите. Точнее, проголосуйте, это уже предложили (кстати, ни одного голоса "за"). https://feedback.azure.com/forums/908035-sql-server/suggestions/32889979-implement-automatically-retrying-deadlock-victims Статус UNPLANNED, но написали. что подумают. Может, если создать новое предложение, и продвигать, то будет результат? |
||
21 фев 19, 21:56 [21816886] Ответить | Цитировать Сообщить модератору |
Lepsik Member Откуда: glubinka Сообщений: 4256 |
не хотите - не пишите ---Меня давно мучает вопрос, почему для транзакции нельзя задать параметры перезапуска на тот случай, если она стала жертвой взаимоблокировки? Для какой именно? может у вас там миллион таких транзакций, а некоторый взрывают реактор. ---Реализовать перехватывание ошибки взаимоблоировки и повторный запуск транзакции - достаточно проблематично и трудоемко. Да ладно, максимум 2 строки. ---Гораздо проще было бы задать два параметра для транзакции на случай ее отката при дедлоке: количество повторных попыток транзакции, временной интервал между повторами транзакции. Это надо на уровне приложения делать, хотя и в драйвер можно запихать.
И не должны. |
||||
21 фев 19, 22:25 [21816902] Ответить | Цитировать Сообщить модератору |
Гавриленко Сергей Алексеевич Member Откуда: Moscow Сообщений: 37198 |
Ага. "Вы, мыши, просто станьте ежиками." (с) Давайте все-таки включим мозг. На минуту, буквально. Вот, допустим, задедлочилась транзакция insert [a] select * from [b] where [b].some_field < ( getdate() - 2 дня ) После, по вашей логике, какую именно транзакцию надо реранить? Варианты реранить ту: Т.е. уже целых 4 варианта как надо реранить запрос в пол строчки. Но, внезапно, тут еще надо учитывать состояние таблицы [a], ибо всякие констрейнты. Уже получается 8 вариантов. И как задавать параметры для этого запроса? А как для скрипта в 20к строк? Рассмотрим альтернативные варианты: Короче, не надо считать себя самым умным, а инжинеров MS самыми тупыми. Сообщение было отредактировано: 22 фев 19, 03:02 |
||||
22 фев 19, 01:35 [21816946] Ответить | Цитировать Сообщить модератору |
aleks222 Member Откуда: Сообщений: 1293 |
Сложно объясняете. 1. После прерывания транзакции ее невозможно запустить "заново". 2. Это уже "другая" транзакция (данные на сервере стали другими) и сервер не может знать "правильная" она или нет. |
||||||
22 фев 19, 07:31 [21816976] Ответить | Цитировать Сообщить модератору |
asdor Member Откуда: Москва Сообщений: 508 |
Artyom E, Странное желание >>Реализовать перехватывание ошибки взаимоблоировки и повторный запуск транзакции - достаточно проблематично и трудоемко. А если сервер отвалился, сетевой сбой, разконектился? Согласен, что такие ошибки должен обрабатывать и разрешать клиент. |
22 фев 19, 10:47 [21817086] Ответить | Цитировать Сообщить модератору |
Владислав Колосов Member Откуда: Сообщений: 8485 |
Artyom E, на самом деле такая возможность есть и называется Job. Ваш бизнес-онлайн, во-первых, вообще не должен валиться с дэдлоками, а вот джобы - сколько угодно и без последствий, оффлайн класс операций. Просто поставьте им ниже приоритет дэдлока. Там как раз и произойдет "Запустите транзакцию повторно" само собой. |
22 фев 19, 18:03 [21817544] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31816 |
Разумеется, если на указанном стейтменте возникла ошибка, нужно перезапустить этот стейтмент. Да, данные на момент повторного запуска (потенциально) изменились, и что, это ненормально, это противоречит каким то принципам РСУБД? Для "скрипта в 20к строк" совершенно то же самое, не вижу разницы по сравнению со скриптом в один INSERT. С теми же параметрами, которые передавались в первый раз. Что тоже никак не противоречит ни академическим теориям СУБД, ни здравому смыслу. Т.е. мы делаем некое атомарное изменение БД, он оне удплось, мы его пробуем повторить, точно так же, как в первый раз, теми же DML с теми же параметрами. Тут очевидные препятствия другие - клиент тоже участвует в транзакции. Например, передаёт данные - не все же клиенты только выполняют запросы, есть же ещё и клиентские курсоры. И если клиент не знает про перезапуск, то это будет непросто сделать. Вообще непонятно, есть ли теоретическая возможность реализовать такую функциональность в MSSQL. Именно в этом проблема, а не в "какую транзакцию ..." или "это уже будет другая транзакция". Artyom E, Но есть решение, про которое уже сказали (сразу же) Сделать это на клиенте. В нормальном проекте доступ к СУБД не размазан тонким слоем по всему коду, а сделан в одной точке. При условии, что управление транзакциями тоже не размазано по всему коду, а сосредоточено в пределах этого метода доступа (то есть один вызов - это атомарное изменение БД), функциональность автоматического перезапуска добавляется в проект очень быстро, нужно просто написать несколько строк в одном месте проекта. |
||
22 фев 19, 23:18 [21817706] Ответить | Цитировать Сообщить модератору |
Гавриленко Сергей Алексеевич Member Откуда: Moscow Сообщений: 37198 |
Сообщение было отредактировано: 23 фев 19, 03:42 |
||||
23 фев 19, 03:40 [21817726] Ответить | Цитировать Сообщить модератору |
SIMPLicity_ Member Откуда: (((@))) Сообщений: 8836 |
Коллеги, последние два сообщения даже я не понял ![]() Изъясняйтесь проще... ПОЖАЛУЙСТА ![]() |
23 фев 19, 09:36 [21817746] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31816 |
Хорошо, тогда можно было бы ограничиться такой опцией для случаев, когда нет транзакций из клиента, правильно? Сиквел не может повторить поток вызовов от клиента, но он же мог бы повторить вызовы от себя? |
||||||||
23 фев 19, 12:11 [21817782] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9683 |
alexeyvg, В общем случае нельзя повторно выполнить транзакцию. Можно лишь повторно выполнить часть транзакции до дедлочащей инструкции включительно. Делать это автоматически нельзя, в силу озвученных выше причин. Итого, об автоповторе можно вести речь, когда транзакция верхнего уровня однобатчевая и в этом батче нету модификаций данных вне транзакции. А это слишком частный случай. |
23 фев 19, 12:53 [21817790] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31816 |
Разве "только если однобатчевая"? По моему, ограничение менее жёсткое - когда клиент в течении транзакции не посылает клиенту запросы (упрощённо можно сказать "когда нет транзакций из клиента"). А внутри сиквела батчей может быть сколько угодно, даже внешних, с DTC и Linked Server. Начали транзакцию, выполняем некий код (процедуры, триггеры, в общем, множество батчей). Если возникла ошибка, транзакция откатилась, и требуется повторный запуск, снова начинаем транзакцию, выполняя тот же код. Не "до дедлочащей инструкции включительно" (как это?), а просто выполняем. Согласен, это очень частный случай, но ИМХО большинство систем с СУБД работают именно так. |
||
23 фев 19, 14:58 [21817833] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31816 |
-- Батч, например, хранимая процедура -- какой то код SELECT ... ... BEGIN TRAN -- Начало транзакции SELECT ... INSERT... UPDATE... COMMIT TRAN -- Конец транзакции -- ещё какой то код ...автоматически преобразует в такой: -- Батч, например, хранимая процедура -- какой то код SELECT ... ... START: BEGIN TRY BEGIN TRAN -- Начало транзакции SELECT ... INSERT... UPDATE... COMMIT TRAN -- Конец транзакции END TRY BEGIN CATCH IF ошибка = дедлок BEGIN ROLLBACK TRAN GOTO START END END CATCH -- ещё какой то код ... |
||
23 фев 19, 15:07 [21817836] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9683 |
Следовательно, нужно сохранять все выполняемое вместе с контекстом выполнения. И даже в этом случае автоматическое повторное выполнение недопустимо, если что-то отсылалось клиенту.
declare @rc int; insert into SomeTable select ... from ... select @rc = @@rowcount; begin tran; ... update AnotherTable ... where @rc > ... ... commit; go |
||||
23 фев 19, 17:07 [21817897] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31816 |
ТЗ для разработчиков МС всё больше и больше :-)
А что в этом неправильного? Я вот вижу, что будет ошибка, если @rc меняется внутри транзакции. Да, это большая проблема, не-откатываемых при ролбаке изменений :-( Т.е. если будет так: declare @rc int; insert into SomeTable select ... from ... select @rc = @@rowcount; begin tran; ... select @rc = @rc + 1 ... -- а вот тут падает на дедлоке update AnotherTable ... where @rc > ... ... commit; go |
||||||||
23 фев 19, 18:20 [21817928] Ответить | Цитировать Сообщить модератору |
Владислав Колосов Member Откуда: Сообщений: 8485 |
Термин "транзакция" следует рассматривать в общем понимании, а у не узкоспециализированном. Тогда смысл сообщения будет понятен. Под транзакцией обычно понимается группа бизнес операций, выполняющаяся как единое целое, например, перевод платежа. Переводя на бытовой язык, "если платеж не прошел, попробуйте еще раз оплатить". |
25 фев 19, 11:32 [21818543] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9683 |
Если транзакция из нескольких батчей и в каком-то из них данные передаются клиенту, то при повторе - нет гаранитии, что клиенту будут переданы те же самые данные; - нет гаранитии, что последующие батчи не зависят от переданных данных. Итого, сервер не может самостоятельно принимать решение об автоматическом повторе транзакции при дедлоке, за исключением тривиальных случаев. Можно лишь попросить МС реализовать механизм повтора, но управляемый сугубо вручную, через указание соответствующих параметров при старте транзакции. Хотя, при нынешнем уровне квалификации разработчиков, я не уверен, что от такого механизма будет больше пользы, чем вреда. |
||
25 фев 19, 12:05 [21818584] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31816 |
Если мы до commit не передаём данные клиенту, то не будет никаких проблем, никаких данных, которые будут неправильными (например, ИД вставленных записей). Когда транзакция завершшится успешно, тогда клиент данные и получит. Конечно, это всё в исходном предположении, что клиент во время транзакции не запускает новые батчи, то есть когда выполняется условие:
Например, если код вообще не содержат транзакций больше чем в один стейтмент - тут вообще без вопросов. Скажем, можно сделать режим "автоматически перезапускать дедлочную транзакцию для одиночных стейтментов без внешней транзакции". Плюс, как я говорил, соблюдая определённые правила (да, они, похоже, достаточно строгию...), такой режим можно использровать и для более сложных транзакций, что разработчики могут применять в проектах, упрощая свой код. |
||||||||
25 фев 19, 12:54 [21818648] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9683 |
|
||
25 фев 19, 13:21 [21818681] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9683 |
|
||
25 фев 19, 13:29 [21818693] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31816 |
Во втором случае, конечно, никаких вариантов. Но повторю - по моему мнению, реально работающие в бизнесе системы редко используют этот второй вариант.
Я ещё раз поясню свою мысль: хочется не волшебной кнопки, которая сделает ошибку 1205 невозможной в MSSQL в принципе (это действительно невозможно). Хочется некую фичу, которая для определённой (и широко распространённой) архитектуре системы, сможет заменить обработку 1205 в приложении. |
||||||||
25 фев 19, 18:25 [21819039] Ответить | Цитировать Сообщить модератору |
SIMPLicity_ Member Откуда: (((@))) Сообщений: 8836 |
Ну просто-таки переопределение страницы 404 ![]() PS .... и на ней, прям точно в серединке, жырная кнопка "За@бись" ![]() |
||
28 фев 19, 14:34 [21821795] Ответить | Цитировать Сообщить модератору |
Все форумы / Microsoft SQL Server | ![]() |