Je jouais avec VACUUM
et j'ai remarqué un comportement inattendu où SELECT
ing lignes d'une table semble réduire le travail que VACUUM
doit faire par la suite.
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);
Maintenant, nous exécutons une mise à jour sur toutes les lignes,
UPDATE numbers SET num = 0;
Et lorsque nous exécutons 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.
Maintenant, nous émettons un autre UPDATE
, mais cette fois nous ajoutons un SELECT
par la suite,
UPDATE numbers SET num = 1;
SELECT * FROM numbers;
Et lorsque nous exécutons 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 que SELECT
supprime les tuples morts des pages qu'elle visite, tout comme VACUUM
?
J'utilise Postgres 11.3 sur macOS 10.14.5.
De ce post sur/r/PostgreSQL à réponse de Laurenz Albe il semble que les mises à jour Heap Only Tuples (HOT) puissent être responsables. D'après la description de Mises à jour CHAUDES dans src/backend/access/heap/README.HOT
En effet, la récupération d'espace se produit pendant la récupération de Tuple lorsque la page est presque pleine (<10% gratuit) et un verrou de nettoyage de tampon peut être acquis. Cela signifie que
UPDATE
,DELETE
etSELECT
peuvent déclencher la récupération d'espace, mais souvent pas pendantINSERT ... VALUES
car il ne récupère pas de ligne.
La citation n'est pas dans la réponse d'origine, mais le reste est une citation,
Pour soutenir ou réfuter cette théorie, exécutez la requête suivante:
SELECT n_tup_upd, n_tup_hot_upd FROM pg_stat_user_tables WHERE schemaname = 'public' AND relname = 'TABLE_NAME';
Si
n_tup_hot_upd
est supérieur à zéro, nous avons un cas.
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).