14.4. Poblar una base de datos #

14.4.1. Desactivar Autocommit
14.4.2. Usar COPY
14.4.3. Eliminar índices
14.4.4. Eliminar restricciones de clave foránea
14.4.5. Aumentar maintenance_work_mem
14.4.6. Aumentar max_wal_size
14.4.7. Desactivar el archivado del WAL y la replicación por transmisión (Streaming Replication)
14.4.8. Ejecutar ANALYZE después
14.4.9. Algunas notas sobre pg_dump

Es posible que necesites insertar una gran cantidad de datos al poblar una base de datos por primera vez. Esta sección contiene algunas sugerencias sobre cómo hacer que este proceso sea lo más eficiente posible.

14.4.1. Desactivar Autocommit #

Al utilizar múltiples sentencias INSERT, desactiva el autocommit y realiza un solo commit al final. (En SQL simple, esto significa emitir BEGIN al principio y COMMIT al final. Algunas bibliotecas de clientes podrían hacer esto por ti, en cuyo caso debes asegurarse de que la biblioteca lo haga cuando tú quieras). Si permites que cada inserción se comprometa por separado, PostgreSQL realiza mucho trabajo por cada fila añadida. Un beneficio adicional de realizar todas las inserciones en una sola transacción es que si la inserción de una fila fallara, la inserción de todas las filas insertadas hasta ese punto se revertiría, por lo que no te quedarás con datos parcialmente cargados.

14.4.2. Usar COPY #

Utiliza COPY para cargar todas las filas en un solo comando, en lugar de utilizar una serie de comandos INSERT. El comando COPY está optimizado para cargar grandes cantidades de filas; es menos flexible que INSERT, pero incurre en una sobrecarga significativamente menor para grandes cargas de datos. Dado que COPY es un solo comando, no es necesario desactivar el autocommit si utilizas este método para poblar una tabla.

Si no puedes utilizar COPY, podría ayudar utilizar PREPARE para crear una sentencia INSERT preparada y luego utilizar EXECUTE tantas veces como sea necesario. Esto evita parte de la sobrecarga de analizar y planificar repetidamente el INSERT. Diferentes interfaces proporcionan esta funcionalidad de diversas formas; busca sentencias preparadas (prepared statements) en la documentación de la interfaz.

Ten en cuenta que cargar una gran cantidad de filas utilizando COPY casi siempre es más rápido que utilizar INSERT, incluso si se utiliza PREPARE y se agrupan múltiples inserciones en una sola transacción.

El comando COPY es más rápido cuando se utiliza dentro de la misma transacción que un comando CREATE TABLE or TRUNCATE anterior. En tales casos, no es necesario escribir en el WAL porque, en caso de error, los archivos que contienen los datos recién cargados se eliminarán de todos modos. Sin embargo, esta consideración solo se aplica cuando wal_level está en minimal, ya que todos los comandos deben escribir en el WAL de lo contrario.

14.4.3. Eliminar índices #

Si estás cargando una tabla recién creada, el método más rápido es crear la tabla, cargar los datos de la tabla de forma masiva utilizando COPY y luego crear los índices necesarios para la tabla. Crear un índice sobre datos ya existentes es más rápido que actualizarlo incrementalmente a medida que se carga cada fila.

Si estás añadiendo grandes cantidades de datos a una tabla existente, podría ser ventajoso eliminar los índices, cargar la tabla y luego recrear los índices. Por supuesto, el rendimiento de la base de datos para otros usuarios podría verse afectado durante el tiempo que falten los índices. También se debe pensar dos veces antes de eliminar un índice único, ya que la comprobación de errores que proporciona la restricción de unicidad se perderá mientras falte el índice.

14.4.4. Eliminar restricciones de clave foránea #

Al igual que con los índices, una restricción de clave foránea se puede comprobar en lote de manera más eficiente que fila por fila. Por lo tanto, podría ser útil eliminar las restricciones de clave foránea, cargar los datos y volver a crear las restricciones. Nuevamente, existe un equilibrio entre la velocidad de carga de datos y la pérdida de comprobación de errores mientras falta la restricción.

Además, cuando cargas datos en una tabla con restricciones de clave foránea existentes, cada nueva fila requiere una entrada en la lista del servidor de eventos de disparadores pendientes (ya que es la ejecución de un disparador lo que comprueba la restricción de clave foránea de la fila). Cargar muchos millones de filas puede hacer que la cola de eventos de disparadores desborde la memoria disponible, provocando un intercambio en disco (swapping) intolerable o incluso el fallo absoluto del comando. Por lo tanto, puede ser necesario, y no solo deseable, eliminar y volver a aplicar las claves foráneas al cargar grandes cantidades de datos. Si no es aceptable eliminar temporalmente la restricción, el único recurso restante puede ser dividir la operación de carga en transacciones más pequeñas.

14.4.5. Aumentar maintenance_work_mem #

Aumentar temporalmente la variable de configuración maintenance_work_mem al cargar grandes cantidades de datos puede mejorar el rendimiento. Esto ayudará a acelerar los comandos CREATE INDEX y ALTER TABLE ADD FOREIGN KEY. No influirá mucho en el propio COPY, por lo que este consejo solo es útil si utilizas una o ambas de las técnicas anteriores.

14.4.6. Aumentar max_wal_size #

Aumentar temporalmente la variable de configuración max_wal_size también puede hacer que las cargas de datos grandes sean más rápidas. Esto se debe a que la carga de una gran cantidad de datos en PostgreSQL provocará que los puntos de control (checkpoints) ocurran con más frecuencia que la habitual (especificada por la variable de configuración checkpoint_timeout). Cada vez que ocurre un punto de control, todas las páginas modificadas (dirty pages) deben volcarse al disco. Al aumentar temporalmente max_wal_size durante las cargas masivas de datos, se puede reducir el número de puntos de control requeridos.

14.4.7. Desactivar el archivado del WAL y la replicación por transmisión (Streaming Replication) #

Al cargar grandes cantidades de datos en una instalación que utiliza el archivado del WAL o la replicación por transmisión, podría ser más rápido realizar una nueva copia de seguridad base (base backup) una vez completada la carga que procesar una gran cantidad de datos del WAL incrementales. Para evitar el registro incremental del WAL durante la carga, desactiva el archivado y la replicación por transmisión configurando wal_level en minimal, archive_mode en off y max_wal_senders en cero. Pero ten en cuenta que cambiar estos ajustes requiere reiniciar el servidor y hace que las copias de seguridad base anteriores no estén disponibles para la recuperación de archivos y el servidor en espera, lo que podría provocar la pérdida de datos.

Además de evitar el tiempo que tardan el archivador o el emisor del WAL en procesar los datos del WAL, hacer esto acelerará ciertos comandos, ya que no escriben en el WAL en absoluto si wal_level es minimal y la subtransacción actual (o la transacción de nivel superior) creó o vació la tabla o el índice que modifican. (Pueden garantizar la seguridad contra fallos de forma más barata realizando un fsync al final que escribiendo en el WAL).

14.4.8. Ejecutar ANALYZE después #

Siempre que hayas alterado significativamente la distribución de datos dentro de una tabla, se recomienda encarecidamente ejecutar ANALYZE. Esto incluye la carga masiva de grandes cantidades de datos en la tabla. Ejecutar ANALYZE (o VACUUM ANALYZE) garantiza que el planificador disponga de estadísticas actualizadas sobre la tabla. Sin estadísticas o con estadísticas obsoletas, el planificador podría tomar decisiones deficientes durante la planificación de consultas, lo que llevaría a un rendimiento deficiente en cualquier tabla con estadísticas inexactas o inexistentes. Ten en cuenta que si el demonio de autovacuum está habilitado, podría ejecutar ANALYZE automáticamente; consulta la Section 24.1.3 y la Section 24.1.6 para más información.

14.4.9. Algunas notas sobre pg_dump #

Los scripts de volcado generados por pg_dump aplican automáticamente varias de las pautas anteriores, pero no todas. Para restaurar un volcado de pg_dump lo más rápido posible, debes realizar algunas acciones adicionales manualmente. (Ten en cuenta que estos puntos se aplican al restaurar un volcado, no al crearlo. Los mismos puntos se aplican tanto si cargas un volcado de texto con psql como si utilizas pg_restore para cargarlo desde un archivo de archivo de pg_dump).

Por defecto, pg_dump utiliza COPY, y cuando genera un volcado completo de esquema y datos, tiene cuidado de cargar los datos antes de crear los índices y las claves foráneas. Así que en este caso varias pautas se gestionan automáticamente. Lo que te queda por hacer es:

  • Establecer valores apropiados (es decir, más grandes de lo normal) para maintenance_work_mem y max_wal_size.

  • Si utilizas el archivado del WAL o la replicación por transmisión, considera desactivarlos durante la restauración. Para ello, configura archive_mode en off, wal_level en minimal y max_wal_senders en cero antes de cargar el volcado. Después, vuelve a configurarlos con sus valores correctos y realiza una nueva copia de seguridad base.

  • Experimenta con los modos de volcado y restauración paralelos de pg_dump y pg_restore y encuentra el número óptimo de trabajos concurrentes a utilizar. Realizar volcados y restauraciones en paralelo mediante la opción -j debería proporcionarte un rendimiento significativamente mayor que el del modo serie.

  • Considera si todo el volcado debería restaurarse como una única transacción. Para hacerlo, pasa la opción de línea de comandos -1 o --single-transaction a psql o pg_restore. Al utilizar este modo, incluso el error más pequeño revertirá toda la restauración, descartando posiblemente muchas horas de procesamiento. Dependiendo de cuán interrelacionados estén los datos, esto podría parecer preferible a una limpieza manual, o no. Los comandos COPY se ejecutarán más rápido si utilizas una única transacción y tienes desactivado el archivado del WAL.

  • Si el servidor de la base de datos dispone de varias CPU, considera el uso de la opción --jobs de pg_restore. Esto permite la carga concurrente de datos y la creación de índices.

  • Ejecuta ANALYZE después.

Un volcado de solo datos seguirá utilizando COPY, pero no elimina ni recrea índices, y no suele tocar las claves foráneas. [14] Por lo tanto, al cargar un volcado de solo datos, depende de ti eliminar y recrear los índices y las claves foráneas si deseas utilizar esas técnicas. Sigue siendo útil aumentar max_wal_size al cargar los datos, pero no te molestes en aumentar maintenance_work_mem; más bien, lo harías al recrear manualmente los índices y las claves foráneas después. Y no olvides ejecutar ANALYZE cuando hayas terminado; consulta la Section 24.1.3 y la Section 24.1.6 para obtener más información.



[14] Puedes conseguir el efecto de desactivar las claves foráneas utilizando la opción --disable-triggers — pero ten en cuenta que esto elimina, en lugar de posponer, la validación de las claves foráneas, por lo que es posible insertar datos incorrectos si la utilizas.