Je jouais avec VACUUM
et j'ai remarqué un comportement inattendu où SELECT
les lignes d'une table semblent réduire le travail VACUUM
à faire par la suite.
Données de test
Remarque: le vide automatique est désactivé
CREATE TABLE numbers (num bigint);
ALTER TABLE numbers SET (
autovacuum_enabled = 'f',
toast.autovacuum_enabled = 'f'
);
INSERT INTO numbers SELECT generate_series(1, 5000);
Essai 1
Maintenant, nous exécutons une mise à jour sur toutes les lignes,
UPDATE numbers SET num = 0;
Et quand nous courons, VACUUM (VERBOSE) numbers;
nous obtenons,
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.
Essai 2
Maintenant, nous en émettons un autre UPDATE
, mais cette fois, nous en ajoutons un SELECT
après,
UPDATE numbers SET num = 1;
SELECT * FROM numbers;
Et quand nous courons, VACUUM (VERBOSE) numbers;
nous obtenons,
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.
Que se passe-t-il exactement ici? Pourquoi la deuxième version que j'exécute, après avoir SELECT
supprimé les tuples morts des pages qu'elle visite, tout comme le VACUUM
fait?
J'exécute Postgres 11.3 sur macOS 10.14.5.
Réponses:
De ce post sur / r / PostgreSQL à une réponse de Laurenz Albe, il semble que les mises à jour Heap Only Tuples (HOT) peuvent être responsables. D'après la description des mises à jour HOT dans
src/backend/access/heap/README.HOT
La citation n'est pas dans la réponse d'origine, mais le reste est une citation,
la source
CREATE INDEX idx_numbers ON numbers USING btree (num)
, la sortie VACUUM passe àINFO: "numbers": removed 5000 row versions in 45 pages
. Notez cependant que dans le scénario sans index,n_tup_hot_upd
est toujours 0, à la fois entre UPDATE et SELECT et entre SELECT et VACUUM. J'ai également veillé à exécuterSELECT pg_sleep(10)
entre chaque instruction afin que les statistiques soient à jour (je voisseq_scan: 2
, une pour la mise à jour et une pour le SELECT).Dans le cas particulier d'une table non indexée, oui, SELECT peut faire le même travail que VACUUM (en ce qui concerne la suppression des lignes mortes).
la source