Estaba jugando VACUUM
y noté un comportamiento inesperado en el que SELECT
las filas de una tabla parecen reducir el trabajo que VACUUM
tiene que hacer después.
Datos de prueba
Nota: autovacuum está deshabilitado
CREATE TABLE numbers (num bigint);
ALTER TABLE numbers SET (
autovacuum_enabled = 'f',
toast.autovacuum_enabled = 'f'
);
INSERT INTO numbers SELECT generate_series(1, 5000);
Prueba 1
Ahora ejecutamos una actualización en todas las filas,
UPDATE numbers SET num = 0;
Y cuando corremos VACUUM (VERBOSE) numbers;
tenemos,
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.
Prueba 2
Ahora emitimos otro UPDATE
, pero esta vez agregamos un SELECT
después,
UPDATE numbers SET num = 1;
SELECT * FROM numbers;
Y cuando corremos VACUUM (VERBOSE) numbers;
tenemos,
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.
¿Qué está pasando exactamente aquí? ¿Por qué la segunda versión que ejecuto, después de SELECT
eliminar las tuplas muertas de las páginas que visita, es bastante similar VACUUM
?
Estoy ejecutando Postgres 11.3 en macOS 10.14.5.
Respuestas:
De esta publicación en / r / PostgreSQL a una respuesta de Laurenz Albe parece que las actualizaciones de Heup Only Tuples (HOT) pueden ser responsables. De la descripción de actualizaciones CALIENTES en
src/backend/access/heap/README.HOT
La cita no está en la respuesta original, pero el resto es una cita,
fuente
CREATE INDEX idx_numbers ON numbers USING btree (num)
, la salida de VACÍO cambia aINFO: "numbers": removed 5000 row versions in 45 pages
. Sin embargo,n_tup_hot_upd
tenga en cuenta que en el escenario sin índice, siempre es 0, tanto entre UPDATE y SELECT como entre SELECT y VACUUM. También me aseguré de ejecutarSELECT pg_sleep(10)
entre cada declaración para que las estadísticas estén actualizadas (veoseq_scan: 2
, una para la ACTUALIZACIÓN y otra para la SELECCIONAR).En el caso especial de una tabla no indexada, sí, SELECT puede hacer el mismo trabajo que VACUUM (en lo que respecta a eliminar filas muertas).
fuente