El crecimiento de la tabla TOAST está fuera de control: FULLVAC no hace nada


9

Recientemente, he actualizado un servidor PostgreSQL 8.2.11 a 8.4 para aprovechar las características de vacío automático y estar en línea con otros 30 servidores PGSQL. Esto fue realizado por un grupo de TI independiente que administra el hardware, por lo que no tenemos muchas opciones en otras actualizaciones (no veremos 9+ por un tiempo). El servidor existe en un entorno muy cerrado (red aislada, privilegios de root limitados) y se ejecuta en RHEL5.5 (i686). Después de la actualización, la base de datos ha crecido constantemente hasta alcanzar los 5-6 GB por día. Normalmente, la base de datos, en su conjunto, es de ~ 20 GB; Actualmente, es ~ 89GB. Tenemos un par de otros servidores que ejecutan bases de datos equivalentes y en realidad sincronizan los registros entre sí a través de una aplicación de terceros (uno que no tengo acceso al funcionamiento interno). Las otras bases de datos son ~ 20GB como deberían ser.

Al ejecutar el siguiente SQL, es bastante obvio que hay un problema con una tabla en particular y, más específicamente, con su tabla TOAST.

SELECT nspname || '.' || relname AS "relation",
    pg_size_pretty(pg_relation_size(C.oid)) AS "size"
  FROM pg_class C
  LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
  WHERE nspname NOT IN ('pg_catalog', 'information_schema')
  ORDER BY pg_relation_size(C.oid) DESC
  LIMIT 20;

Que produce:

              relación | Talla  
------------------------------------ + ---------  
  pg_toast.pg_toast_16874 | 89 GB  
  fews00.warmstates | 1095 MB  
  ...  
(20 filas)

Esta tabla TOAST es para una tabla llamada "series de tiempo" que guarda grandes registros de datos blobbados. Uno SUM(LENGTH(blob)/1024./1024.)de todos los registros en series de tiempo produce ~ 16 GB para esa columna. No debería haber ninguna razón para que la tabla TOAST de esta tabla sea tan grande como es.

He realizado un VACUUM FULL VERBOSE ANALYZE timeseries, y el vacío se ejecuta hasta su finalización sin errores.

INFO: aspirar "pg_toast.pg_toast_16874"
INFO: "pg_toast_16874": se encontraron 22483 versiones removibles, 10475318 no removibles en 10448587 páginas
DETALLE: 0 versiones muertas aún no se pueden eliminar.
Las versiones de fila no extraíbles varían de 37 a 2036 bytes de longitud.
Hubo 20121422 punteros de elementos no utilizados.
El espacio libre total (incluidas las versiones de fila extraíbles) es de 0 bytes. 4944885 páginas están o estarán vacías, incluido 0 al final de la tabla. 4944885 páginas que contienen 0 bytes libres son posibles destinos de movimiento.
CPU 75.31s / 29.59u sec transcurrido 877.79 sec.
INFORMACIÓN: el índice "pg_toast_16874_index" ahora contiene 10475318 versiones de fila en 179931 páginas
DETALLE: Se eliminaron 23884 versiones de fila de índice.
Se han eliminado 101623 páginas de índice, 101623 son actualmente reutilizables.
CPU 1.35s / 2.46u sec transcurrido 21.07 sec.

REINDEXed la tabla que liberó un poco de espacio (~ 1GB). No puedo agrupar la tabla ya que no hay suficiente espacio en el disco para el proceso, y estoy esperando reconstruir la tabla por completo, ya que me gustaría descubrir por qué es mucho más grande que las bases de datos equivalentes que tenemos.

Ejecuté una consulta desde el wiki de PostgreSQL aquí: "Mostrar hinchazón de la base de datos" , y esto es lo que obtengo:

current_database | Schemaname | nombre de tabla | tbloat | desechos desperdiciados | iname | ibloat | wastedibytes  
----------------- + ------------ + ------------------- ------------- + -------- + ------------- + ------------- -------------------- + -------- + --------------  
ptrdb04 | fews00 | series de tiempo | 1.0 | 0 | idx_timeseries_synchlevel | 0,0 | 0 0  
ptrdb04 | fews00 | series de tiempo | 1.0 | 0 | idx_timeseries_localavail | 0,0 | 0 0  
ptrdb04 | fews00 | series de tiempo | 1.0 | 0 | idx_timeseries_expirytime | 0,0 | 0 0  
ptrdb04 | fews00 | series de tiempo | 1.0 | 0 | idx_timeseries_expiry_null | 0,0 | 0 0  
ptrdb04 | fews00 | series de tiempo | 1.0 | 0 | uniq_localintid | 0,0 | 0 0  
ptrdb04 | fews00 | series de tiempo | 1.0 | 0 | pk_timeseries | 0,1 | 0 0  
ptrdb04 | fews00 | idx_timeseries_expiry_null | 0.6 | 0 | ? El | 0,0 | 0 0

Parece que la base de datos no considera este espacio como "vacío" en absoluto, ¡pero no veo de dónde viene todo el espacio en disco!

Sospecho que este servidor de base de datos está decidiendo usar 4-5 veces más espacio en disco para guardar los mismos registros extraídos de los otros servidores de datos. Mi pregunta es esta: ¿hay alguna forma de verificar el tamaño del disco físico de una fila? Me gustaría comparar el tamaño de una fila en esta base de datos con otra base de datos "saludable".

¡Gracias por cualquier ayuda que usted nos pueda proporcionar!

ACTUALIZACIÓN 1

Terminé reconstruyendo la tabla a partir de un esquema volcado debido a su tamaño (no podía dejarlo solo para otro día). Después de sincronizar los datos, a través del proceso de sincronización del software, la tabla TOAST fue de ~ 35 GB; sin embargo, solo pude dar cuenta de ~ 9 GB de esa columna de blob, que debería ser la más larga en términos de valores. No estoy seguro de dónde provienen los otros 26 GB. CLUSTERADO, VACÍO LLENO y REINDEXADO en vano. Los archivos postgresql.conf entre los servidores de datos locales y remotos son exactamente iguales. ¿Hay alguna razón por la que esta base de datos podría estar intentando almacenar cada registro con un espacio más grande en el disco?

ACTUALIZACIÓN 2 - Fijo

Finalmente decidí reconstruir completamente la base de datos desde cero, incluso llegando a reinstalar los paquetes PostgreSQL84 en el sistema. La ruta de la base de datos se reinicializó y los espacios de tablas se limpiaron. El proceso de sincronización de software de terceros repobló las tablas, ¡y el tamaño final resultó ser ~ 12GB ! Desafortunadamente, esto, de ninguna manera, ayuda a resolver cuál fue la fuente exacta del problema aquí. Lo veré durante un día o dos y veré si hay diferencias importantes con la forma en que la base de datos revitalizada maneja la tabla TOAST y publicaré esos resultados aquí.

Tamaño de relación


ptrdb04=> SELECT nspname || '.' || relname AS "relation",
ptrdb04->     pg_size_pretty(pg_relation_size(C.oid)) AS "size"
ptrdb04->   FROM pg_class C
ptrdb04->   LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
ptrdb04->   WHERE nspname NOT IN ('pg_catalog', 'information_schema')
ptrdb04->   ORDER BY pg_relation_size(C.oid) DESC
ptrdb04->   LIMIT 2;

        relación          |   tamaño   
 ------------------------- + --------- 
 pg_toast . pg_toast_17269 | 18 GB 
 Fews00 . estados cálidos        | 1224 MB
 ( 2 filas )  

VACUUM VERBOSE ANALYZE timeseries;

INFORMACIÓN: "series de tiempo": se encontraron 12699 versiones removibles, 681961 filas no removibles en 58130 de 68382 páginas
DETALLE: 0 versiones de fila muerta no se pueden eliminar todavía.
Hubo 105847 punteros de elementos no utilizados.
0 páginas están completamente vacías.
CPU 0.83s / 2.08u sec transcurrido 33.36 sec.
INFORMACIÓN: aspirar "pg_toast.pg_toast_17269"
INFORMACIÓN: índice escaneado "pg_toast_17269_index" para eliminar las versiones de fila 2055849
DETALLE: CPU 0.37s / 2.92u sec transcurrido 13.29 sec.
INFORMACIÓN: "pg_toast_17269": se eliminaron 2055849 versiones de fila en 518543 páginas
DETALLE: CPU 8.60s / 3.21u sec transcurrido 358.42 sec.
INFORMACIÓN: el índice "pg_toast_17269_index" ahora contiene 7346902 versiones de fila en 36786 páginas
DETALLE: se eliminaron las versiones de la fila del índice 2055849.
Se han eliminado 10410 páginas de índice, 5124 son actualmente reutilizables.
CPU 0.00s / 0.00u sec transcurrido 0.01 sec.
INFORMACIÓN: "pg_toast_17269": se encontraron 1286128 extraíbles, 2993389 versiones de filas no extraíbles en 1257871 de 2328079 páginas
DETALLE: 0 versiones de fila muerta no se pueden eliminar todavía.
Hubo 18847 punteros de elementos no utilizados.
0 páginas están completamente vacías.
CPU 26.56s / 13.04u sec transcurrido 714.97 sec.
INFORMACIÓN: analizando "fews00.timeseries"
INFORMACIÓN: "series de tiempo": escaneadas 30000 de 68382 páginas, que contienen 360192 filas activas y 0 filas muertas; 30000 filas en la muestra, 821022 filas totales estimadas

La única diferencia notable después de la reconstrucción (que no sea el uso del disco) es

INFORMACIÓN: "pg_toast_17269": se encontraron 1286128 extraíbles, 2993389 versiones de filas no extraíbles
como @CraigRinger mencionó en un comentario. El recuento de filas no extraíbles es mucho menor que antes.

Nueva pregunta: ¿Pueden otras tablas afectar el tamaño de otra tabla? (a través de claves externas y similares) La reconstrucción de la tabla no hizo nada, pero reconstruir toda la base de datos probó solucionar el problema.


¿Por qué no actualizaste directamente a 9.2? Tiene incluso más mejoras en el área de vacío que 8.4 (y 8.4 irá EOL el año que viene de todos modos)
a_horse_with_no_name

He actualizado la publicación. La actualización no fue realizada por nuestra tienda y no necesariamente por nuestra solicitud. Desafortunadamente, no tenemos esa opción para actualizar a 9+.
BrM13

OKAY. Solo quería asegurarme de que no
pasaras por

Respuestas:


9

Esta:

INFO: "pg_toast_16874": found 22483 removable, 10475318 nonremovable row versions in 10448587 pages 22483 removable, 10475318 nonremovable row versions in 10448587 pages

sugiere que el problema subyacente es que algo todavía puede "ver" esas filas para que no se puedan eliminar.

Los candidatos para eso son:

  • Perdió transacciones preparadas. Cheque pg_catalog.pg_prepared_xacts; Debería estar vacío. También corre SHOW max_prepared_transactions; debería reportar cero.

  • Sesiones de larga duración con una transacción abierta e inactiva. En PostgreSQL 8.4 y superior, esto solo debería ser un problema para las SERIALIZABLEtransacciones. Compruebe pg_catalog.pg_stat_activityde <IDLE> in transactionsesiones.

Lo más probable es que tenga un cliente que no puede confirmar o deshacer transacciones durante largos períodos de inactividad.

Si esto no resulta ser, lo siguiente que comprobaría sería hacer una suma octet_sizede cada columna de la tabla de interés. Compare eso con el pg_relation_sizede la mesa y su TOASTmesa auxiliar. Si hay una gran diferencia, es probable que el espacio consumido ya no sea por filas visibles y que probablemente tenga problemas de hinchazón en la tabla. Si son bastante similares, puede comenzar a reducir dónde está el uso del espacio al sumar los tamaños de octetos por columna, obtener los valores superiores 'n', etc.


1) pg_prepared_xacts y max_prepared_transactions volvieron vacías. 2) Definitivamente hay algunas transacciones IDLE de las SELECT * FROM pg_stat_activity WHERE current_query LIKE '<IDLE>%';cuales se obtienen unos 30-40 resultados; Sin embargo, esto parece bastante normal. Revisé algunos servidores "saludables", y eran lo mismo.
BrM13

3) Esto es lo que hice. En bucle a través de columnas de series temporales, tirando octet_length (columna). Multiplica cada valor por el recuento de filas y los suma. Para series de tiempo, obtuve ~ 430MB (cerca de los 493MB de pg_relation_size) y 438MB para la tabla TOAST (usando las columnas chunk_id, chunk_seq, chunk_data). Las estimaciones parecen correctas, y la tabla TOAST está muy lejos del tamaño de la relación en aproximadamente 2 órdenes de magnitud (60 GB en la actualidad). Parece que tengo hinchazón, pero no el tipo tradicional (hinchazón no utilizada). De lo contrario, un FULLVAC debería solucionar el problema.
BrM13

@Brad Las sesiones inactivas están bien, solo las sesiones inactivas con transacciones abiertas son un problema, es decir <IDLE> in transaction, y solo si (a) han estado inactivas durante un tiempo y (b) están usando SERIALIZABLEaislamiento o estás en 8.3 o mayor.
Craig Ringer

@Brad Sin embargo, es interesante que solo la TOASTtabla parezca estar hinchada. Por cierto, si ha estado usando VACUUM FULLmucho en un servidor anterior a 9.0, querrá hacerlo, REINDEXya que VACUUM FULLen esas versiones podría causar una hinchazón de índice significativa. Ahora me pregunto si alguien ha puesto un absurdo FILLFACTORen la mesa de pan tostado, aunque eso no debería permitirle pasar más de 10 veces el consumo de espacio.
Craig Ringer el

Gracias por la aclaración IDLE. Supuse que a eso te referías, pero es bueno saberlo con certeza. En cuanto a FILLFACTOR, la tabla está usando el valor predeterminado. FYI: de acuerdo con la documentación 8.4 CREATE TABLE, el valor predeterminado es 100 y no puede establecer un FILLFACTOR para la tabla TOAST.
BrM13

0

No tengo ninguna idea de por qué está hinchado. Pero busqué un poco y tal vez este enlace tiene alguna idea: http://postgresql.1045698.n5.nabble.com/A-154-GB-table-swelled-to-527-GB-on-the-Slony-slave -Cómo compactarlo td5543034.html ... No es su situación exacta, pero tal vez sea lo suficientemente cerca como para ayudarlo a llegar al fondo de la hinchazón fantasma.

Sin embargo, creo que la única forma de compactar esa tabla en este momento es CLUSTERARLA. Como tiene poco espacio en disco, eso es un problema.

Aquí está mi sugerencia para eso: cree un espacio de tabla en una unidad diferente con mucho espacio adicional, luego asigne su tabla de problemas a ese espacio de tabla. PostgreSQL copiará la tabla al nuevo espacio de tabla (probablemente bloqueando la tabla en el proceso, por lo que necesitará una ventana de mantenimiento). Luego, VACHA TODO la tabla (borra la mayor parte del espacio anterior consumido por la tabla en el espacio de tabla predeterminado). Luego CLUSTER la mesa y se debe compactar sola. Luego, vuelva a colocarlo en el espacio de tabla predeterminado y ejecute VACFULL nuevamente (para borrar el espacio no utilizado en el nuevo espacio de tabla).


De hecho, terminé reconstruyendo la tabla (volcando el esquema y reconstruyéndolo a partir de eso) y extrayendo los datos directamente de una de las bases de datos remotas. Después de que se realizó el proceso, la base de datos todavía tenía 35 GB, con solo 9 GB representados por una columna de blob "ancho". CLUSTERED, VACUUM FULLed, REINDEXed, y todavía estoy sentado en una tonelada de uso misterioso del disco.
BrM13

Link está muerto :(
hayd
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.