Pull to refresh

Comments 25

Это нормально, что софтверный продукт даже в простейшем кейсе пытается отстрелить новичку конечность?

Я таки думаю, что применительно к СУБД не существует понятия "простейший кейс".

Абсолютно не нормально. Бд фиксирует deadlock, но не понимает, что блокировки строк в пределах одной транзакции?!! Это не может быть нормальным.

простите, а вы как статью то читаете? там даже в примере два параллельных конкурирующих апдейта

Хм, видимо по диагонали. Был не прав, вспылил. Ок, postgresql реабилитирован - это прям гора с плеч! Но, извините, тогда и статья ни о чем.... в том смысле, что конкуренцию в транзакциях надо учитывать в любой бд.

Извините а можете прям цитату привести в статье о том что идут 2 (или больше) паралельных UPDATE запроса? Или я шото подзабыл и UPDATE из коробки выполняется паралельно для всех записей из WHERE

Примерно вот тут:

Давайте взглянем на проблему под немного другим углом, разложив на составляющие.

Как поступает пара конкурирующих UPDATE: ...

Прочитал статью и так же сразу не понял, что речь идет о двух конкурирующих транзакций. Статья начинается с того, что ловится deadlock на операции UPDATE и сразу возникает вопрос, а как это может быть. Начинаешь читать дальше и предлагается взглянуть под другим углом. Но не слово о том, что этот дидлок изначально был вызван двумя транзакциями.

конечно, потому что бд нацелена на весьма тонкий баланс производительность / надежность, и сортировки при любых действиях будут давать очень заметное понижение производительности

Откуда берутся болячки блокировочника, если PostgreSQL версионник?

Нет тут никаких болячек. Любой версионник тоже блокирует измененные строки, но при этом он не мешает читающим транзакциям видеть предыдущие версии строк (снэпшоты). А вот другие модифицирующие транзакции, если попытаются изменить те же самые строки, вынуждены будут подождать, пока первая транзакция не завершится и не "отпустит" их, и лишь затем смогут продолжать работу.

Статья напоминает о том, что порядок обработки строк в общем случае непредсказуем, и часто зависит от физического расположения строк в блоках на диске. И если 2 параллельные сессиии возьмутся обновлять одни и те же наборы строк, то мы можем получить взаимоблокировку.

Это классическая проблема, и автор в данной статье приводит её хрестоматийное решение. Многие новички сталкиваются с этим, и ломают голову потому что не понимают как работает СУБД.

Спасибо за ваши статьи, @Kilor :)

То есть ситуация — декларативный алгоритм не работает, поэтому мы декларативно опишем императивный алгоритм вместо того, чтобы написать его императивно. Кажется мир ушел куда-то не туда.

Вообще очень странная ситуация. Вроде бы как UPDATE должен быть атомарным, а тут выходит, что нет — каждую строку отдельно блокирует? Какая же это атомарность? В него посредине могут залезть и заблокировать его данные. Может у вас настройки изоляции транзакций какие-то неправильные стояли? Просто это выглядит дичью

Вот это "должен быть атомарным" - очень смелое утверждение, на основании чего?

Просто, есть желания/домыслы разработчика-пользователя, а есть фактическая реализация внутри PG. И они не всегда совпадают.

На основании принципов ACID?

Эти принципы постулируют несколько иное, если мы про A[CID]:

Атомарность гарантирует, что никакая транзакция не будет зафиксирована в системе частично. Будут либо выполнены все её подоперации, либо не выполнено ни одной.

Речь про атомарность результирующего состояния, но не про атомарность наложения всего множества блокировок.

тоже не понял как одинаковые UPDATE могут задедлочить. обе транзакции попытаются в одинаковом порядке вычитать записи, соответственно наложить блокировку должны одинаково попытаться. одной транзакции это удастся, другой нет.

накладывая блокировки в том самом порядке, в котором мы их физически прочитали с носителя

Собственно, в этом и проблема - порядок чтения с носителя негарантирован.

Это неточность так утверждать. Собственно порядок чтения с носителя тут не так важен, может случиться так, что из за оптимизаций сканирования таблиц и прочих оптимизаций просто порядок выполнения апдейтов и локов будет другой. Тут не только дело в том, что с диска что то прочитается в другом порядке.

Так UPDATE и обрабатывает запись (переписывает кортеж и накладывает блокировку) ровно в порядке чтения со страницы данных, если явно не указано иное.

Каюсь, не понял, почему возникает блокировка.

>Получается, сначала подходящие под условие строки были в "каком-то" порядке прочитаны, а уже после этого UPDATE стал их менять, накладывая блокировки в том самом порядке, в котором мы их физически прочитали с носителя.

ну прочитала БД строки в случайном порядке и меняет их одну за одной. Но блокировка то откуда?

Имеется ввиду, что соседняя транзакция читает ту же таблицу в другом порядке и блокирует строки одну за одной по другому? Т.е. транзакция А блокирует строки 1,2,3 а транзакция Б блокирует строки 2,1,3 и на блокировке строк 1 и 2 их и деллочит?

Я правильно понял или тут в другом дело?

Именно так - неодинаковый порядок наложения блокировок на записи - в нем и дело.

Т.е. в принципе у нас любой update который меняет более одной строки в недетерминированном порядке может вызвать deadlock.

Я вот сейчас задумался почему я раньше с этим не сталкивался - думаю потому, что в большинстве приложений с которыми я раньше имел дело изменения были однострочными

Как лучше с таким бороться. Я подозреваю если вероятность не высокая, то навреное лучше всего фэйлить операцию в целом и пусть дальше механизм retry за нас доделывает. Потому, что массово писать код как это показано в статье - нет никакой возможности.

Т.е. в принципе у нас любой update который меняет более одной строки в недетерминированном порядке может вызвать deadlock.

100%

лучше всего фэйлить операцию в целом и пусть дальше механизм retry за нас доделывает

Она зафейлится автоматически при сработке дедлока. А вот механизм ретрая делать надо самим тогда.

Sign up to leave a comment.