sql >> Base de Datos >  >> RDS >> PostgreSQL

Una descripción general del procesamiento VACUUM en PostgreSQL

PostgreSQL no utiliza un mecanismo de actualización IN-SITU, por lo que según la forma en que se diseñaron los comandos ELIMINAR y ACTUALIZAR,

  • Cada vez que se realizan operaciones DELETE, marca la tupla existente como MUERTA en lugar de eliminar físicamente esas tuplas.
  • Del mismo modo, cada vez que se realiza la operación ACTUALIZAR, marca la tupla existente correspondiente como MUERTA e inserta una nueva tupla (es decir, operación ACTUALIZAR =ELIMINAR + INSERTAR).

Así que cada comando ELIMINAR y ACTUALIZAR dará como resultado una tupla MUERTA, que nunca se usará (a menos que haya transacciones paralelas). Estas tuplas inactivas darán lugar a un uso de espacio adicional innecesario, incluso si el número de registros efectivos es igual o menor. Esto también se llama expansión del espacio en PostgreSQL. Dado que PostgreSQL se usa ampliamente como tipo OLTP de sistema de base de datos relacional, donde se llevan a cabo operaciones frecuentes de INSERCIÓN, ACTUALIZACIÓN y ELIMINACIÓN, habrá muchas tuplas MUERTAS y, por lo tanto, las consecuencias correspondientes. Por lo tanto, PostgreSQL requería un fuerte mecanismo de mantenimiento para lidiar con estas tuplas MUERTAS. VACUUM es el proceso de mantenimiento que se ocupa de tratar con la tupla DEAD junto con algunas actividades más útiles para optimizar la operación de VACUUM. Comprendamos algo de la terminología que se usará más adelante en este blog.

Mapa de visibilidad

Como su nombre lo indica, mantiene la información de visibilidad sobre las páginas que contienen solo tuplas que se sabe que son visibles para todas las transacciones activas. Para cada página, se utiliza un bit. Si el bit se establece en 1, significa que todas las tuplas de la página correspondiente son visibles. El bit establecido en 0 significa que no hay espacio libre en la página dada y las tuplas pueden ser visibles para todas las transacciones.

El mapa de visibilidad se mantiene para cada relación (tabla e índice) y se asocia junto con las relaciones principales, es decir, si el nombre del nodo del archivo de relación es 12345, entonces el archivo de visibilidad se almacena en el archivo paralelo 12345_vm.

Mapa de espacio libre

Mantiene información de espacio libre que contiene detalles sobre el espacio disponible en la relación. Esto también se almacena en el archivo paralelo al archivo principal de relación, es decir, si el nombre del nodo del archivo de relación es 12345, entonces el archivo de mapa de espacio libre se almacena en el archivo paralelo 12345_fsm.

Congelar tupla

PostgreSQL usa 4 bytes para almacenar la identificación de la transacción, lo que significa que se pueden generar un máximo de 2 mil millones de transacciones antes de que finalice. Ahora considere todavía en este momento que alguna tupla contiene la identificación de transacción inicial, digamos 100, luego para la nueva transacción (que usa la transacción envuelta), digamos 5, la identificación de transacción 100 mirará hacia el futuro y no podrá ver los datos agregados /modificado por él a pesar de que en realidad fue en el pasado. Para evitar este id de transacción especial, se asigna FrozenTransactionId (igual a 2). Esta identificación de transacción especial siempre se considera en el pasado y será visible para todas las transacciones.

VACÍO

El trabajo principal de VACUUM es recuperar el espacio de almacenamiento ocupado por las tuplas DEAD. El espacio de almacenamiento recuperado no se devuelve al sistema operativo, sino que simplemente se desfragmenta dentro de la misma página, por lo que solo están disponibles para ser reutilizados por la futura inserción de datos dentro de la misma tabla. Mientras que la operación VACUUM se realiza en una tabla en particular, al mismo tiempo se pueden realizar otras operaciones de LECTURA/ESCRITURA en la misma tabla, ya que no se toma el bloqueo exclusivo en la tabla en particular. En caso de que no se especifique un nombre de tabla, se realizará VACUUM en todas las tablas de la base de datos. La operación VACUUM realiza una serie de operaciones dentro de un bloqueo ShareUpdateExclusive:

  • Escanea todas las páginas de todas las tablas (o tabla especificada) de la base de datos para obtener todas las tuplas inactivas.
  • Congele las tuplas antiguas si es necesario.
  • Elimine la tupla índice que apunta a las respectivas tuplas MUERTAS.
  • Eliminar las tuplas MUERTAS de una página correspondiente a una tabla específica y reasignar las tuplas activas en la página.
  • Actualizar el mapa de espacio libre (FSM) y el mapa de visibilidad (VM).
  • Si es posible, trunque la última página (si hubo tuplas MUERTAS que se liberaron).
  • Actualice todas las tablas del sistema correspondientes.

Como podemos ver en los pasos de trabajo anteriores para VACUUM, está claro que es una operación muy costosa ya que necesita procesar todas las páginas de la relación. Por lo que es muy necesario saltarse posibles páginas que no requieran ser aspiradas. Dado que el mapa de visibilidad (VM) brinda información de la página donde, si no hay espacio libre, se puede suponer que no se requiere el vacío de página correspondiente y, por lo tanto, esta página se puede omitir de manera segura.

Dado que VACUUM de todos modos recorre todas las páginas y todas sus tuplas, por lo que aprovecha la oportunidad para realizar otra tarea importante de congelar las tuplas calificadas.

VACÍO completo

Como se discutió en la sección anterior, aunque VACUUM elimina todas las tuplas DEAD y desfragmenta la página para uso futuro, no ayuda a reducir el almacenamiento general de la tabla, ya que en realidad no se libera espacio para el Sistema operativo. Supongamos que una tabla tbl1 indica que el almacenamiento total ha llegado a 1,5 GB y de este 1 GB está ocupado por una tupla inactiva; luego, después de VACUUM, habrá aproximadamente 1 GB disponible para insertar más tuplas, pero aún así, el almacenamiento total seguirá siendo de 1,5 GB.

Full VACUUM resuelve este problema liberando espacio y devolviéndolo al sistema operativo. Pero esto tiene un costo. A diferencia de VACUUM, FULL VACUUM no permite la operación en paralelo ya que requiere un bloqueo exclusivo en la relación que obtiene FULL VACUUMed. A continuación se muestran los pasos:

  • Toma bloqueo exclusivo en la relación.
  • Cree un archivo de almacenamiento paralelo vacío.
  • Copie todas las tuplas activas del almacenamiento actual al almacenamiento recién asignado.
  • Luego, libere el almacenamiento original.
  • Libere el candado.

Entonces, como se desprende de los pasos también, tendrá almacenamiento solo requerido para los datos restantes.

VACÍO automático

En lugar de hacer VACUUM manualmente, PostgreSQL admite un demonio que activa automáticamente VACUUM periódicamente. Cada vez que VACUUM se despierta (por defecto 1 minuto) invoca múltiples trabajos (dependiendo de los procesos de configuración autovacuum_worker).

Los trabajadores de vacío automático realizan procesos de VACÍO simultáneamente para las respectivas mesas designadas. Dado que VACUUM no tiene ningún bloqueo exclusivo en las tablas, no tiene (o tiene un impacto mínimo) en el trabajo de otras bases de datos.

La configuración de Auto-VACUUM debe realizarse en función del patrón de uso de la base de datos. No debe ser demasiado frecuente (ya que desperdiciará la activación de los trabajadores, ya que puede que no haya o muy pocas tuplas muertas) ni demasiado retrasado (causará muchas tuplas muertas juntas y, por lo tanto, se hinchará la mesa).

VACÍO o VACÍO total

Idealmente, la aplicación de la base de datos debe diseñarse de manera que no sea necesario el VACÍO COMPLETO. Como se explicó anteriormente, FULL VACUUM recrea el espacio de almacenamiento y vuelve a colocar los datos, por lo que si solo hay menos tuplas muertas, inmediatamente se recreará el espacio de almacenamiento para volver a colocar todos los datos originales. Además, dado que FULL VACUUM tiene un bloqueo exclusivo en la tabla, bloquea todas las operaciones en la tabla correspondiente. Entonces, hacer FULL VACUUM a veces puede ralentizar la base de datos general.

En resumen, se debe evitar el VACÍO completo a menos que se sepa que la mayor parte del espacio de almacenamiento se debe a tuplas inactivas. La extensión de PostgreSQL pg_freespacemap se puede usar para obtener una pista clara sobre el espacio libre.

Veamos un ejemplo del proceso VACÍO explicado.

Primero, creemos una tabla demo1:

postgres=# create table demo1(id int, id2 int);

CREATE TABLE

E inserte algunos datos allí:

postgres=# insert into demo1 values(generate_series(1,10000), generate_series(1,

10000));

INSERT 0 10000

postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');

 npages | average_freespace_ratio

--------+-------------------------

  45 |                0.00

(1 row)

Ahora, eliminemos datos:

postgres=# delete from demo1 where id%2=0;

DELETE 5000

Y ejecute una aspiradora manual:

postgres=# vacuum demo1;

VACUUM

postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');

 npages | average_freespace_ratio

--------+-------------------------

  45 |               45.07

(1 row)

Este espacio libre ahora está disponible para ser reutilizado por PostgreSQL, pero si desea liberar ese espacio para el sistema operativo, ejecute:

postgres=# vacuum full demo1;

VACUUM

postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');

 npages | average_freespace_ratio

--------+-------------------------

  23 |                0.00

(1 row)

Conclusión

Y este fue un breve ejemplo de cómo funciona el proceso VACÍO. Afortunadamente, gracias al proceso de vacío automático, la mayoría de las veces y en un entorno común de PostgreSQL, no necesita pensar en esto porque lo administra el propio motor.