Comments 20
Параллельно выполняющийся запрос нам мешает — ведь он когда-то может захотеть обратиться к этим версиям (а вдруг?), и они должны быть ему доступны. И поэтому даже VACUUM FULL нам не поможет.
Если параллельный запрос вам мешает — вы не сможете взять access exclusive.
VACUUM FULL
все же накладывает эксклюзивную блокировку (ожидает завершения транзакций на таблице). Проверить просто — открыть два окна, в одном начать транзакцию и выбрать что-то из таблицы, в другом выполнитьVACUUM FULL
. Он не начнется пока не будет завершена транзакция в другом окне.
Соглашусь с предыдущим комментарием — выглядит так, как будто можно заменить на
SET statement_timeout = '1s';
VACUUM FULL table_name;
VACUUM FULL VERBOSE tbl;
INFO: vacuuming "public.tbl"
INFO: "tbl": found 0 removable, 10026 nonremovable row versions in 45 pages
DETAIL: 10000 dead row versions cannot be removed yet.
А так — да, логически они полностью идентичны, кроме момента, что VF сохраняет MVCC и не может быть выполнен внутри транзакции.
Ого. Интересно.Заставило почитать исходный код. Вы ведь используете репликацию с hot_standby_feedback? Как я понял standby вычисляет и посылает в этом случае ид транзакции с мастера (на standby нет своих номеров транзакций), которая еще хранит нужные ему строки и мастер не очищает строки чтобы не удалить строки которые нужны на standby.
При этом truncate таким не страдает и спокойно очищает строки. Интересно, vacuum full это по сути запрос cluster, но в нем все равно проверяется какие строки должны оставаться видимы.
egorov, звучит как тема для еще одной статьи — как работает host_standby_feedback и на что он влияет на мастере)
Спасибо за статью, узнал про запрос TABLE
.
Возник вопрос — чем не подошел pg_repack?
И еще дополнение — в приведенном запросе имена индексов не сохранятся, добавится префикс swap. И так каждый раз.
CREATE TABLE _swap_%table(LIKE %table INCLUDING ALL);
INSERT INTO _swap_%table TABLE %table;
DROP TABLE %table;
ALTER TABLE _swap_%table RENAME TO %table;
Полезное дело делаете!
Пара уточнений.
Да и последующие запросы по этой таблице пойдут у нас по «горячему кэшу»
Vacuum использует буферное кольцо в кеше, чтобы не вымывать из него полезные данные. Обратная сторона медали — в кеше ничего (почти ничего) не останется после его работы.
Для этого нам необходимо включить SERIALIZABLE-изоляцию для нашей транзакции
Достаточно и Read Committed, вы же вручную ставите блокировку.
С READ COMMITED возникала, насколько помню, проблема при обращении параллельной транзакции. Вот только последний раз проверял такой кейс под реальной нагрузкой чуть ли не на 9.1 — возможно, был какой-то баг.
Кольцо — одно на операцию. По сути, это просто кусочек общего кеша, который из него временно «откушен».
Думаю, ускорение там из-за того, что vacuum full ведь тоже чистит ненужные версии строк, ну и если перед этим vacuum уже прошелся, то и ему легче.
Насчёт Read Committed — скорее всего в чем-то другом дело было. Против Access Exclusive не попрешь.
(К тому же Serializable работает только если и остальные транзакции используют тот же уровень. Иначе все это выражается в Repeatable Read.)
Про кольца нигде особо не написано, но погрепайте buffer ring в исходниках.
Об очень похожем метода мы рассказывали совсем недавно на YaTalks — https://youtu.be/hXH_tRBxFnA 05:02:53 (извиняюсь не смог с телефона получить точную ссылку — секция про очереди, доклад "Как Толока росла вместе с кластером PostgreSQL").
Не знал, что есть способ обойти MVCC. )
Нашел в документации соответствующее предупреждение:
«Команда TRUNCATE небезопасна с точки зрения MVCC. После опустошения таблицы она будет выглядеть пустой для параллельных транзакций, если они работают со снимком, полученным до опустошения.»
DBA: когда пасует VACUUM — чистим таблицу вручную