Postgres Professional corporate blog
PostgreSQL
SQL
Comments 11
0
«Блокировки отношений»
Постргес Про, кажется перегибают палку в дословности перевода.
+2

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


Можете что-то лучше предложить?

0
«Таблицы, и индексы, и последовательности, и материализованные представления»
Объекты?
0

Если б все так просто. Блокировки объектов в статье тоже есть. Но эти объекты также включают номера транзакций, версии строк, страницы и проч. А мне надо выделить именно отношения.
Можно, конечно, вместо блокировки объектов говорить просто блокировки (надеясь не спутать их с другими видами блокировок), а вместо отношенийобъекты, но что-то мне кажется, что ясности это не прибавит.

+1

Расскажите, пожалуйста, про create index concurrently.


  1. Почему, например, его создание может сломаться (если это не уникальный индекс, конечно)?
  2. Почему система, если видит, что индекс сломался во время создания, просто не дропнет его сама же? Зачем это приходится делать руками?
+2
Почему, например, его создание может сломаться

Из-за взаимоблокировок. Чтобы объяснить, придется углубиться в детали… Там происходит хитросложный трехфазный процесс.




Фаза 1.


Начинаем транзакцию.
Блокируем таблицу, на которой собираемся строить индекс, в режиме ShareUpdateExclusive.
Регистрируем индекс в системном каталоге, помечаем его как не готовый для вставок и не валидный.
Фиксируем транзакцию (но блокировка ShareUpdateExclusive остается, она берется до конца сеанса).


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


Фаза 2.


Начинаем транзакцию.


(Ожидание 1) Поскольку еще могут быть транзакции со старыми снимками данных, еще не увидевшие появление индекса, необходимо их подождать. Фактически мы ждем все, что конфликтует с уровнем Share, то есть любые пишущие транзакции.


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


Готовый ко вставкам (pg_index.indisready) означает, что теперь все транзакции будут обновлять этот индекс.


Фаза 3.


Начинаем транзакцию.


(Ожидание 2) Поскольку еще могут быть транзакции со старыми снимками данных, не успевшие понять, что индекс надо обновлять, необходимо их подождать.


Полностью сканируем таблицу и обновляем построенный индекс так, чтобы в него попало то, что мы упустили во время фазы 2. (А все новые строки уже будут вставляться, так как мы объявили индекс готовым ко вставкам.)


(Ожидание 3) Поскольку еще могут быть транзакции со старыми снимками данных, необходимо их подождать.


Фиксируем транзакцию.
Помечаем индекс как валидный (pg_index.indisvalid), чтобы его можно было использовать.
Освобождаем блокировку таблицы SharedUpdateExclusive.




Собственно, проблема в тех трех местах, в которых происходит ожидание.
Например:


  • начнет выполняться CREATE INDEX CONCURRENTLY и захватывает блокировку ShareUpdateExclusive;
  • какая-то транзакция пытается выполнить что-нибудь несовместимое (например, ANALYZE или какой-нибудь DDL) и повисает;
  • CREATE INDEX CONCURRENTLY доходит до точки ожидания, видит транзакцию со старым снимком и ждет ее завершения — deadlock detected!

Если хочется еще подробностей, можно заглянуть в commands/indexcmds.c и catalog/index.c (функция validate_index).

+2
Почему система, если видит, что индекс сломался во время создания, просто не дропнет его сама же? Зачем это приходится делать руками?

Не знаю. Наверное, чтобы не городить что-то вокруг стандартной процедуры обнаружения и разрешения взаимоблокировок. Убили процесс и убили, ну а все что он успел зафиксировать — осталось.

+1

тут может быть полезно упомянуть про lock_timeout и statement_timeout, когда лучше упасть VACUUM FULL (из примера или другие операции с подобных эффектом) и потом разбираться, что пошло не так, чем ждать их завершения

Only those users with full accounts are able to leave comments., please.