Bawiłem się VACUUM
i zauważyłem pewne nieoczekiwane zachowanie, w którym SELECT
wstawianie wierszy z tabeli wydaje się zmniejszać VACUUM
późniejszą pracę.
Dane testowe
Uwaga: autovacuum jest wyłączone
CREATE TABLE numbers (num bigint);
ALTER TABLE numbers SET (
autovacuum_enabled = 'f',
toast.autovacuum_enabled = 'f'
);
INSERT INTO numbers SELECT generate_series(1, 5000);
Próba 1
Teraz uruchamiamy aktualizację dla wszystkich wierszy,
UPDATE numbers SET num = 0;
A kiedy biegniemy VACUUM (VERBOSE) numbers;
, dostajemy
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.
Próba 2
Teraz wydajemy inny UPDATE
, ale tym razem dodajemy SELECT
później,
UPDATE numbers SET num = 1;
SELECT * FROM numbers;
A kiedy biegniemy VACUUM (VERBOSE) numbers;
, dostajemy
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.
Co dokładnie się tutaj dzieje? Dlaczego druga wersja, którą uruchamiam, po SELECT
usunięciu martwych krotek ze stron, które odwiedza, zupełnie jak VACUUM
robi?
Używam Postgres 11.3 na macOS 10.14.5.
Odpowiedzi:
Od tego postu na / r / PostgreSQL do odpowiedzi Laurenz Albe wydaje się, że aktualizacje Heap Only Tuples (HOT) mogą być odpowiedzialne. Z opisu HOT aktualizacji w
src/backend/access/heap/README.HOT
Cytat nie jest w oryginalnej odpowiedzi, ale reszta jest cytatem,
źródło
CREATE INDEX idx_numbers ON numbers USING btree (num)
, wyjście VACUUM zmieni się naINFO: "numbers": removed 5000 row versions in 45 pages
. Należy jednak pamiętać, że w scenariuszu bez indeksun_tup_hot_upd
zawsze wynosi 0, zarówno między AKTUALIZACJĄ a WYBOREM oraz między WYBOREM a VACUUM. Upewniłem się również, że biegamSELECT pg_sleep(10)
między każdą instrukcją, aby statystyki były aktualne (widzęseq_scan: 2
, jedną dla UPDATE i jedną dla SELECT).W szczególnym przypadku nieindeksowanej tabeli, tak, SELECT może wykonać tę samą pracę co VACUUM (jeśli chodzi o usuwanie martwych wierszy).
źródło