Порядок блокировок в запросе (postgresql)

В базе данных есть таблица X и таблицы An, Bn, Cn, Dn, которые унаследованы от X.

Процесс 1 периодически запрашивает данные из X.

Процесс 2 обновляет данные в дочерних таблицах. Например, для обновления таблиц An и Bn он создает новые таблицы Am и Bm, загружает в них данные, блокирует монопольный доступ An, Bn, удаляет An и Bn и изменяет Am и Bm, чтобы они наследовали X.

Проблема в том, что когда процесс 1 выполняет запрос (например select * from X) он блокирует таблицы An, Bn, Cn, Dn в разделяемом режиме, и порядок блокировки неизвестен. Если процесс 1 блокирует Bn, то процесс 2 блокирует An, и мы имеем взаимоблокировку.

Есть ли информация о порядке блокировки таблиц в запросах в postgresql (без явной блокировки)? Или может быть возможны другие решения?


person valodzka    schedule 27.06.2010    source источник
comment
SELECT не блокирует таблицу, если только вы явно не запросите блокировку. Вы проверили pg_locks, чтобы увидеть, что происходит? postgresql.org/docs/8.4/interactive/view-pg- замки.html   -  person Frank Heikens    schedule 28.06.2010
comment
SELECT блокирует таблицу (postgresql.org/docs/8.1/static/explicit- locking.html), и в моем случае это конфликтует с эксклюзивным доступом, запрошенным drop. ACCESS SHARE Конфликтует только с режимом блокировки ACCESS EXCLUSIVE. Команды SELECT и ANALYZE устанавливают блокировку этого режима на таблицы, на которые ссылаются. В общем, любой запрос, который только читает таблицу и не изменяет ее, получит этот режим блокировки.   -  person valodzka    schedule 28.06.2010
comment
Он конфликтует из-за ACCESS EXCLUSIVE, это ваша проблема. Сам SELECT не является проблемой.   -  person Frank Heikens    schedule 28.06.2010
comment
DROP тоже не проблема. Это конфликтует из-за ACCESS SHARE SELECT :)   -  person valodzka    schedule 29.06.2010


Ответы (2)


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

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

person Donnie    schedule 27.06.2010
comment
Я немного упростил: процесс 1 не является пакетным заданием, это действительно много процессов, которые выполняют множество разных запросов. Будет очень неприятно использовать явную блокировку для каждого запроса. Если бы порядок postgresql был предсказуемым, было бы намного проще изменить порядок блокировки процесса 2. - person valodzka; 28.06.2010
comment
Вот почему вы не должны чрезмерно упрощать свои вопросы. Тем не менее, варианты остаются прежними: либо выполнять явную блокировку, либо обрабатывать взаимоблокировки при сбое (поскольку postgres обнаруживает взаимоблокировки и убивает один из вовлеченных процессов, чтобы другой мог завершить это вариант). - person Donnie; 28.06.2010

Есть ли информация о порядке блокировки таблиц в запросах в postgresql (без явной блокировки)? Или может быть возможны другие решения?

Обычно реализация postgresql mvcc защитит вас от многих типов взаимоблокировок. См. http://www.postgresql.org/files/developer/transactions.pdf для более подробной информации.

Тем не менее, одно из распространенных решений состоит в том, чтобы просто обрабатывать тупиковые ситуации, то есть, если ваш запрос завершается ошибкой из-за тупиковой ситуации, попробуйте еще раз.

person nos    schedule 27.06.2010