Удаляет ли SELECT мертвые строки, как VACUUM?

9

Я возился с VACUUMи заметил некоторое неожиданное поведение, когда SELECTизвлечение строк из таблицы, кажется, сокращает объем работы, VACUUMкоторую необходимо выполнить впоследствии.

Тестовые данные

Примечание: автовакуум отключен

CREATE TABLE numbers (num bigint);
ALTER TABLE numbers SET (
  autovacuum_enabled = 'f',
  toast.autovacuum_enabled = 'f'
);

INSERT INTO numbers SELECT generate_series(1, 5000);

Испытание 1

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

UPDATE numbers SET num = 0;

И когда мы бежим, VACUUM (VERBOSE) numbers;мы получаем,

INFO:  vacuuming "public.numbers"
INFO:  "numbers": removed 5000 row versions in 23 pages
INFO:  "numbers": found 5000 removable, 5000 nonremovable row versions in 45 out of 45 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 6585
There were 0 unused item pointers.

Испытание 2

Теперь мы выпускаем другой UPDATE, но на этот раз мы добавим SELECTпотом,

UPDATE numbers SET num = 1;
SELECT * FROM numbers;

И когда мы бежим, VACUUM (VERBOSE) numbers;мы получаем,

INFO:  vacuuming "public.numbers"
INFO:  "numbers": removed 56 row versions in 22 pages
INFO:  "numbers": found 56 removable, 5000 nonremovable row versions in 45 out of 45 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 6586
There were 56 unused item pointers.

Что именно здесь происходит? Почему вторая версия, которую я запускаю, после SELECTудаления мертвых кортежей со страниц, которые он посещает, совсем как VACUUMделает?

Я использую Postgres 11.3 на macOS 10.14.5.

rafbm
источник
2
Какой клиент вы используете для запуска ваших команд? В нем включен автокоммит?
mustaccio
2
Я собираюсь удалить вопрос "Является ли таблица VACUUM в основном просто SELECT * FROM таблицей под капотом?" (это не так). Я думаю, что это хорошее продолжение, ответ здесь прост: SELECT может удалять мертвые строки, и он разделяет это с VACUUM. Чем они отличаются, будет очень исчерпывающим разговором о переносе XID и множеством других вещей. Этот вопрос в основном звучит так: «Что еще делает пылесос, кроме удаления мертвых строк». (Что было бы отчасти смутно)
Эван Кэрролл
@mustaccio Я провел эти тесты со скриптом на Ruby, используя ActiveRecord, который использует гем PG под капотом. Я полагаю, что автокоммит включен по умолчанию, так как вам не нужно выдавать COMMIT, если BEGIN не используется явно.
rafbm

Ответы:

5

Из этого поста в / r / PostgreSQL к ответу Лоренца Альбе кажется, что ответственность за обновления могут вносить только Heap Only Tuples (HOT). Из описания горячих обновлений вsrc/backend/access/heap/README.HOT

По сути, восстановление пространства происходит во время поиска кортежа, когда страница почти заполнена (<10% свободна) и может быть получена блокировка очистки буфера. Это означает, что UPDATE, DELETEи SELECTможет вызвать восстановление пространства, но часто не во время, INSERT ... VALUESпотому что он не извлекает строку.

Цитата не в оригинальном ответе, но остальное цитата,

Чтобы поддержать или опровергнуть эту теорию, выполните следующий запрос:

SELECT n_tup_upd, n_tup_hot_upd
FROM pg_stat_user_tables
WHERE schemaname = 'public' AND relname = 'TABLE_NAME';

Если n_tup_hot_updбольше нуля, у нас есть дело.

Эван Кэрролл
источник
Сейчас мы говорим. +1
mustaccio
ГОРЯЧЕЕ, кажется, хорошее объяснение. Если я CREATE INDEX idx_numbers ON numbers USING btree (num), VACUUM выход изменится на INFO: "numbers": removed 5000 row versions in 45 pages. Однако обратите внимание, что в сценарии без индекса n_tup_hot_updвсегда 0, как между UPDATE и SELECT, так и между SELECT и VACUUM. Я также удостоверился, что бегал SELECT pg_sleep(10)между каждым оператором так, чтобы статистика была актуальной (я вижу seq_scan: 2, один для ОБНОВЛЕНИЯ и один для ВЫБОР).
rafbm
В этом случае select генерирует WAL? У меня сложилось впечатление, что выборка вообще не генерирует WAL. Если да, это будет означать, что удаление мертвых строк распространяется на любых рабов. Если нет, это означает, что пылесос все еще необходим на подчиненном устройстве. Это также означает, что хозяева и рабы не идентичны. Хм, может быть, мне нужно провести некоторое исследование и опубликовать вопрос и / или ответ или два.
Colin 't Hart
1

В особом случае неиндексированной таблицы, да, SELECT может выполнять ту же работу, что и VACUUM (в том, что касается удаления мертвых строк).

jjanes
источник
3
Не могли бы вы добавить объяснение?
Лоренц Альбе