¿Por qué VACUUM ANALYZE no eliminaría todas las tuplas muertas?

8

Ejecutamos un "manual" VACUUM ANALYZE VERBOSEen algunas de nuestras tablas más grandes después de hacer DELETE/INSERTcambios importantes en ellas. Esto parece funcionar sin problemas, aunque a veces el VACUUMtrabajo de una tabla se ejecutará durante horas (consulte esta publicación para problemas y razonamientos similares).

Al investigar más, descubrí que tenemos tablas grandes con una gran cantidad de tuplas muertas incluso después de correr VACUUM. Por ejemplo, estas son algunas de las estadísticas producidas a partir de la consulta en esta respuesta .

-[ RECORD 50 ]--+---------------------------
relname         | example_a
last_vacuum     | 2014-09-23 01:43
last_autovacuum | 2014-08-01 01:19
n_tup           |    199,169,568
dead_tup        |    111,048,906
av_threshold    |     39,833,964
expect_av       | *
-[ RECORD 51 ]--+---------------------------
relname         | example_b
last_vacuum     | 2014-09-23 01:48
last_autovacuum | 2014-08-30 12:40
n_tup           |    216,596,624
dead_tup        |    117,224,220
av_threshold    |     43,319,375
expect_av       | *
-[ RECORD 52 ]--+---------------------------
relname         | example_c
last_vacuum     | 2014-09-23 01:55
last_autovacuum | 2014-09-23 18:25
n_tup           |    309,831,136
dead_tup        |    125,047,233
av_threshold    |     61,966,277
expect_av       | *

El último campo indica que estas (y la mayoría de las tablas) alcanzarían el umbral para autovacuum. Sin embargo, después de haber corrido VACUUM ANALYZE VEBOSEen cada una de esas tablas, ¿no debería el recuento de tuplas muertas ser 0 (o cercano a 0, no 125M de 300M)?

La documentación dice:

VACUUM reclama el almacenamiento ocupado por tuplas muertas.

¿Esto significa que nuestro VACUUMno está funcionando?


ACTUALIZAR

Por solicitud en respuesta aquí hay algunos registros de los VERBOSEtrabajos:

INFO:  vacuuming "public.example_1"
INFO:  scanned index "idx_example_1_on_gp_id_and_dd_id" to remove 378386 row versions
DETAIL:  CPU 1.83s/3.42u sec elapsed 23.01 sec.
INFO:  scanned index "index_example_1_on_q_id" to remove 378386 row versions
DETAIL:  CPU 2.10s/3.91u sec elapsed 18.92 sec.
INFO:  "example_1": removed 378386 row versions in 7085 pages
DETAIL:  CPU 0.09s/0.05u sec elapsed 0.19 sec.
INFO:  index "idx_example_1_on_gp_id_and_dd_id" now contains 30347438 row versions in 291065 pages
DETAIL:  378386 index row versions were removed.
165587 index pages have been deleted, 164287 are currently reusable.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  index "index_example_1_on_q_id" now contains 30347438 row versions in 333287 pages
DETAIL:  378386 index row versions were removed.
152773 index pages have been deleted, 152757 are currently reusable.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  "example_1": found 1773 removable, 401984 nonremovable row versions in 14438 out of 1493006 pages
DETAIL:  0 dead row versions cannot be removed yet.
There were 10567 unused item pointers.
0 pages are entirely empty.
CPU 4.26s/7.51u sec elapsed 46.10 sec.
INFO:  vacuuming "pg_toast.pg_toast_17917"
INFO:  index "pg_toast_17917_index" now contains 0 row versions in 1 pages
DETAIL:  0 index row versions were removed.
0 index pages have been deleted, 0 are currently reusable.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  "pg_toast_17917": found 0 removable, 0 nonremovable row versions in 0 out of 0 pages
DETAIL:  0 dead row versions cannot be removed yet.
There were 0 unused item pointers.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  analyzing "public.example_1"
INFO:  "example_1": scanned 30000 of 1493006 pages, containing 611502 live rows and 0 dead rows; 30000 rows in sample, 40563141 estimated total rows

Esta tabla ahora muestra 0 tuplas muertas en las estadísticas. La mayoría de las tablas son tuplas muertas mucho más bajas esta mañana, por lo que nuestro VACUUMautovacuum está funcionando.

Tenemos un puñado de tablas que no muestran nada y aún muestran tuplas muertas:

-[ RECORD 49 ]--+---------------------------
relname         | example_2
last_vacuum     | 2014-09-23 02:23
last_autovacuum | 2014-09-02 14:30
n_tup           |    117,914,944
dead_tup        |     34,507,388
av_threshold    |     23,583,039
expect_av       | *

Un par de veces he visto en los registros donde se comprobarán los índices una y otra vez. Esto parece corresponder a VACUUMtrabajos de larga duración . ¿Alguna idea de por qué? ¿Esto solo funciona alrededor del bloqueo de registros (no creo que haya ninguna escritura durante esta ejecución de trabajos).

INFO:  vacuuming "public.example_2"
...
INFO:  scanned index "index_example_2_on_gsg_id_and_dd_id" to remove 2795959 row versions
DETAIL:  CPU 3.88s/16.54u sec elapsed 23.09 sec.
INFO:  scanned index "index_example_2_on_q_id" to remove 2795959 row versions
DETAIL:  CPU 6.74s/21.13u sec elapsed 84.64 sec.
INFO:  "example_2": removed 2795959 row versions in 48214 pages
DETAIL:  CPU 0.71s/0.32u sec elapsed 33.65 sec.
INFO:  scanned index "index_example_2_on_gsg_id_and_dd_id" to remove 2591011 row versions
DETAIL:  CPU 2.84s/16.11u sec elapsed 19.28 sec.
INFO:  scanned index "index_example_2_on_q_id" to remove 2591011 row versions
DETAIL:  CPU 5.46s/22.70u sec elapsed 130.57 sec.
INFO:  "example_2": removed 2591011 row versions in 45539 pages
DETAIL:  CPU 0.67s/0.38u sec elapsed 15.16 sec.
INFO:  index "index_example_2_on_gsg_id_and_dd_id" now contains 123807784 row versions in 1560915 pages
DETAIL:  108836958 index row versions were removed.
1100790 index pages have been deleted, 718471 are currently reusable.
CPU 0.00s/0.00u sec elapsed 0.25 sec.
INFO:  index "index_example_2_on_q_id" now contains 123807784 row versions in 1886087 pages
DETAIL:  110336259 index row versions were removed.
1058063 index pages have been deleted, 266983 are currently reusable.
CPU 0.00s/0.00u sec elapsed 0.07 sec.
INFO:  "example_2": found 124808 removable, 1355901 nonremovable row versions in 2086343 out of 6966379 pages
DETAIL:  0 dead row versions cannot be removed yet.
There were 7858495 unused item pointers.
0 pages are entirely empty.
CPU 595.49s/2130.13u sec elapsed 5656.34 sec.
INFO:  vacuuming "pg_toast.pg_toast_18079"
INFO:  index "pg_toast_18079_index" now contains 0 row versions in 1 pages
DETAIL:  0 index row versions were removed.
0 index pages have been deleted, 0 are currently reusable.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  "pg_toast_18079": found 0 removable, 0 nonremovable row versions in 0 out of 0 pages
DETAIL:  0 dead row versions cannot be removed yet.
There were 0 unused item pointers.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  analyzing "public.example_2"
INFO:  "example_2": scanned 30000 of 6966379 pages, containing 528443 live rows and 522 dead rows; 30000 rows in sample, 152953760 estimated total rows
jwadsack
fuente
0 dead row versions cannot be removed yet.indica que no tiene transacciones de larga duración que bloquearían la eliminación de tuplas muertas.
Erwin Brandstetter

Respuestas:

10

VACUUM solo puede eliminar tuplas muertas que están muertas hace mucho tiempo, es decir, muertas para todos los usos posibles. Si tiene transacciones de larga duración, pueden evitar que se eliminen las tuplas recientemente muertas.

Este es un ejemplo de una situación en la que una transacción de larga duración impidió la eliminación:

INFO:  "pgbench_accounts": found 0 removable, 2999042 nonremovable row versions in 49181 out of 163935 pages
DETAIL:  2999000 dead row versions cannot be removed yet.

No se trata realmente de transacciones de larga duración, sino de instantáneas de larga duración. Ciertamente, una declaración de selección o inserción de larga duración hará eso. Para niveles de aislamiento superiores a lectura confirmada, toda la transacción retendrá la instantánea hasta que esté inactiva, por lo que si alguna abre una transacción de lectura repetible y luego se va de vacaciones sin comprometerla, eso sería un problema. Las transacciones preparadas colgadas también lo harán (si no sabe qué es una transacción preparada, entonces probablemente no las esté usando).

Los ejemplos que muestra no indican un problema, pero también dice que el problema se había resuelto para entonces. Si este es un problema recurrente, probablemente debería comenzar a registrar la salida de sus declaraciones VACUUM VERBOSE, para que pueda encontrar la información que cubre el período durante el cual existe el problema.

Los pases múltiples sobre el índice se deben a la configuración de maintenance_work_mem. Solo puede eliminar una tupla por cada 6 bytes de memoria en cada pasada sobre el índice, y necesita hacer varias pasadas si necesita eliminar más que eso. Por lo tanto, ayudar a mantener_work_mem_mem.

jjanes
fuente
¿Puede dar un ejemplo de lo que podría ser una "transacción de larga duración"? ¿Te refieres a una consulta de base de datos de larga ejecución o INSERT/ IMPORT? ¿O quieres decir algo más largo que una conexión abierta / cerrada?
jwadsack
4

El tamaño de la tabla física generalmente (excepto para la poda oportunista de páginas extraíbles desde el final de la tabla) no se reduce al ejecutarse VACUUM(o VACUUM ANALYZE). Necesitas correr VACUUM FULLpara reducir la mesa.

Esta es una cita de la respuesta relacionada, que tiene más detalles:

Por documentación (solo unas pocas líneas debajo de su presupuesto, en realidad):

Simple VACUUM(sin FULL) simplemente reclama espacio y lo pone a disposición para su reutilización. Esta forma del comando puede funcionar en paralelo con la lectura y escritura normal de la tabla, ya que no se obtiene un bloqueo exclusivo. Sin embargo, no se devuelve espacio adicional al sistema operativo (en la mayoría de los casos);

Más aquí:

Te interesará pg_repack , que puede hacer lo mismo que VACUUM FULLsin bloqueos exclusivos.

Erwin Brandstetter
fuente
1
Lo siento si mi pregunta no estaba clara, pero estaba preguntando sobre las tuplas muertas restantes. Sé que VACUUMsin FULLno reducirá el tamaño en el disco, y estoy de acuerdo con eso. Mencioné una tabla grande debido a la publicación que primero vinculé al afirmar que una estrategia de vacío agresiva ajustada sería una "victoria ... si hay tablas grandes cuyas filas nunca se eliminan ni actualizan". Nuestras mesas grandes se cambian a diario.
jwadsack