Ich spielte mit VACUUM
und bemerkte ein unerwartetes Verhalten, bei dem SELECT
Zeilen aus einer Tabelle die Arbeit zu reduzieren scheinen, die VACUUM
danach zu erledigen ist.
Testdaten
Hinweis: Das automatische Vakuum ist deaktiviert
CREATE TABLE numbers (num bigint);
ALTER TABLE numbers SET (
autovacuum_enabled = 'f',
toast.autovacuum_enabled = 'f'
);
INSERT INTO numbers SELECT generate_series(1, 5000);
Versuch 1
Jetzt führen wir ein Update für alle Zeilen durch.
UPDATE numbers SET num = 0;
Und wenn wir rennen VACUUM (VERBOSE) numbers;
, bekommen wir,
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.
Versuch 2
Jetzt geben wir eine andere heraus UPDATE
, aber dieses Mal fügen wir eine SELECT
nachträgliche hinzu,
UPDATE numbers SET num = 1;
SELECT * FROM numbers;
Und wenn wir rennen VACUUM (VERBOSE) numbers;
, bekommen wir,
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.
Was genau passiert hier? Warum funktioniert die zweite Version, die ich nach dem SELECT
Entfernen toter Tupel von den besuchten Seiten ausführe , ganz so VACUUM
?
Ich verwende Postgres 11.3 unter macOS 10.14.5.
Antworten:
Von diesem Beitrag auf / r / PostgreSQL bis zu einer Antwort von Laurenz Albe scheint es, dass Heap Only Tuples (HOT) -Updates verantwortlich sein könnten. Aus der Beschreibung der HOT-Updates in
src/backend/access/heap/README.HOT
Das Zitat ist nicht in der ursprünglichen Antwort, aber der Rest ist ein Zitat,
quelle
CREATE INDEX idx_numbers ON numbers USING btree (num)
, wechselt die VACUUM-Ausgabe zuINFO: "numbers": removed 5000 row versions in 45 pages
. Beachten Sie jedoch, dass im Szenario ohne Indexn_tup_hot_upd
immer 0 ist, sowohl zwischen UPDATE und SELECT als auch zwischen SELECT und VACUUM. Ich habe auch darauf geachtet,SELECT pg_sleep(10)
zwischen den einzelnen Anweisungen zu laufen , damit die Statistiken auf dem neuesten Stand sind (ich seheseq_scan: 2
, eine für das UPDATE und eine für das SELECT).Im speziellen Fall einer nicht indizierten Tabelle kann SELECT die gleiche Arbeit wie VACUUM ausführen (was das Entfernen toter Zeilen betrifft).
quelle