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

7 consejos de mejores prácticas para la carga masiva de datos de PostgreSQL

A veces, las bases de datos de PostgreSQL necesitan importar grandes cantidades de datos en un solo paso o en un número mínimo de pasos. Esto se conoce comúnmente como importación masiva de datos, donde la fuente de datos suele ser uno o más archivos grandes. Este proceso a veces puede ser inaceptablemente lento.

Hay muchas razones para un rendimiento tan bajo:los índices, los disparadores, las claves foráneas, las claves primarias GUID o incluso el registro de escritura anticipada (WAL) pueden causar retrasos.

En este artículo, cubriremos algunos consejos de mejores prácticas para la importación masiva de datos en bases de datos PostgreSQL. Sin embargo, puede haber situaciones en las que ninguno de estos consejos sea una solución eficaz. Recomendamos a los lectores que consideren los pros y los contras de cualquier método antes de aplicarlo.

Sugerencia 1:cambie la tabla de destino al modo no registrado

Para PostgreSQL 9.5 y versiones posteriores, la tabla de destino se puede modificar primero a NO REGISTRAR y luego volver a modificarla a REGISTRO una vez que se cargan los datos:

ALTER TABLE <target table> SET UNLOGGED
<bulk data insert operations…>
ALTER TABLE <target table> LOGGED

El modo UNLOGGED garantiza que PostgreSQL no envíe operaciones de escritura de tablas al registro de escritura anticipada (WAL). Esto puede hacer que el proceso de carga sea significativamente más rápido. Sin embargo, dado que las operaciones no se registran, los datos no se pueden recuperar si se produce un bloqueo o un apagado incorrecto del servidor durante la carga. PostgreSQL truncará automáticamente cualquier tabla no registrada una vez que se reinicie.

Además, las tablas no registradas no se replican en servidores en espera. En tales casos, las replicaciones existentes deben eliminarse antes de la carga y volver a crearse después de la carga. Según el volumen de datos en el nodo principal y la cantidad de nodos en espera, el tiempo para recrear la replicación puede ser bastante largo y no aceptable para los requisitos de alta disponibilidad.

Recomendamos las siguientes prácticas recomendadas para la inserción masiva de datos en tablas no registradas:

  • Hacer una copia de seguridad de la tabla y los datos antes de cambiarlos a un modo no registrado
  • Recrear cualquier replicación en servidores en espera una vez que se completa la carga de datos
  • Uso de inserciones masivas no registradas para tablas que se pueden volver a llenar fácilmente (por ejemplo, tablas de búsqueda grandes o tablas de dimensiones)

Consejo 2:eliminar y volver a crear índices

Los índices existentes pueden causar retrasos significativos durante las inserciones masivas de datos. Esto se debe a que, a medida que se agrega cada fila, también se debe actualizar la entrada de índice correspondiente.

Recomendamos colocar índices en la tabla de destino siempre que sea posible antes de iniciar la inserción masiva y volver a crear los índices una vez que se complete la carga. Una vez más, la creación de índices en tablas grandes puede llevar mucho tiempo, pero generalmente será más rápido que actualizar los índices durante la carga.

DROP INDEX <index_name1>, <index_name2> … <index_name_n>
<bulk data insert operations…>
CREATE INDEX <index_name> ON <target_table>(column1, …,column n)

Puede valer la pena aumentar temporalmente el maintenance_work_mem parámetro de configuración justo antes de crear los índices. El aumento de la memoria de trabajo puede ayudar a crear los índices más rápido.

Otra opción para ir a lo seguro es hacer una copia de la tabla de destino en la misma base de datos con los datos e índices existentes. Esta tabla recién copiada se puede probar con inserción masiva para ambos escenarios:índices de soltar y volver a crear o actualizarlos dinámicamente. Luego se puede seguir el método que produce un mejor rendimiento para la tabla en vivo.

Consejo 3:Suelte y vuelva a crear claves foráneas

Al igual que los índices, las restricciones de clave externa también pueden afectar el rendimiento de la carga masiva. Esto se debe a que cada clave externa en cada fila insertada debe verificarse para verificar la existencia de una clave principal correspondiente. Detrás de escena, PostgreSQL usa un disparador para realizar la verificación. Al cargar una gran cantidad de filas, este disparador debe activarse para cada fila, lo que aumenta la sobrecarga.

A menos que las reglas comerciales lo restrinjan, recomendamos eliminar todas las claves externas de la tabla de destino, cargar los datos en una sola transacción y luego volver a crear las claves externas después de confirmar la transacción.

ALTER TABLE <target_table> 
DROP CONSTRAINT <foreign_key_constraint>

BEGIN TRANSACTION
<bulk data insert operations…>
COMMIT

ALTER TABLE <target_table> 
ADD CONSTRAINT <foreign key constraint>  
FOREIGN KEY (<foreign_key_field>) 
REFERENCES <parent_table>(<primary key field>)...

Una vez más, aumentando el maintenance_work_mem El parámetro de configuración puede mejorar el rendimiento de la recreación de restricciones de clave externa.

Consejo 4:deshabilitar disparadores

Los activadores INSERT o DELETE (si el proceso de carga también implica la eliminación de registros de la tabla de destino) pueden provocar retrasos en la carga masiva de datos. Esto se debe a que cada disparador tendrá una lógica que debe verificarse y operaciones que deben completarse justo después de que se INSERTE o ELIMINE cada fila.

Recomendamos deshabilitar todos los activadores en la tabla de destino antes de cargar datos de forma masiva y habilitarlos después de que finalice la carga. La desactivación de TODOS los disparadores también incluye disparadores del sistema que imponen verificaciones de restricciones de clave externa.

ALTER TABLE <target table> DISABLE TRIGGER ALL
<bulk data insert operations…>
ALTER TABLE <target table> ENABLE TRIGGER ALL

Sugerencia 5:utilice el comando COPIAR

Recomendamos usar PostgreSQL COPY Comando para cargar datos de uno o más archivos. COPY está optimizado para cargas masivas de datos. Es más eficiente que ejecutar una gran cantidad de declaraciones INSERT o incluso INSERCIONES de varios valores.

COPY <target table> [( column1>, … , <column_n>)]
FROM  '<file_name_and_path>' 
WITH  (<option1>, <option2>, … , <option_n>)

Otros beneficios de usar COPY incluyen:

  • Admite la importación de archivos binarios y de texto
  • Es de naturaleza transaccional
  • Permite especificar la estructura de los archivos de entrada
  • Puede cargar datos condicionalmente usando una cláusula WHERE

Sugerencia 6:utilice INSERCIÓN de varios valores

Ejecutar varios miles o varios cientos de miles de declaraciones INSERT puede ser una mala elección para la carga masiva de datos. Esto se debe a que cada comando INSERT individual debe ser analizado y preparado por el optimizador de consultas, pasar por todas las comprobaciones de restricciones, ejecutarse como una transacción separada y registrarse en el WAL. El uso de una declaración INSERT única de varios valores puede ahorrar esta sobrecarga.

INSERT INTO <target_table> (<column1>, <column2>, …, <column_n>) 
VALUES 
(<value a>, <value b>, …, <value x>),
(<value 1>, <value 2>, …, <value n>),
(<value A>, <value B>, …, <value Z>),
(<value i>, <value ii>, …, <value L>),
...

El rendimiento de INSERT de varios valores se ve afectado por los índices existentes. Recomendamos descartar los índices antes de ejecutar el comando y volver a crear los índices después.

Otra área a tener en cuenta es la cantidad de memoria disponible para PostgreSQL para ejecutar INSERT de varios valores. Cuando se ejecuta un INSERT de varios valores, una gran cantidad de valores de entrada tiene que caber en la RAM y, a menos que haya suficiente memoria disponible, el proceso puede fallar.

Recomendamos configurar el effect_cache_size parámetro al 50 % y shared_buffer parámetro al 25% de la memoria RAM total de la máquina. Además, para estar seguro, ejecuta una serie de INSERT de varios valores con cada declaración que tiene valores para 1000 filas.

Sugerencia 7:Ejecute ANALIZAR

Esto no está relacionado con la mejora del rendimiento de la importación masiva de datos, pero recomendamos enfáticamente ejecutar ANALIZAR comando en la tabla de destino inmediatamente después la importación a granel. Una gran cantidad de filas nuevas sesgará significativamente la distribución de datos en columnas y hará que las estadísticas existentes en la tabla estén desactualizadas. Cuando el optimizador de consultas utiliza estadísticas obsoletas, el rendimiento de las consultas puede ser inaceptablemente bajo. Ejecutar el comando ANALIZAR garantizará que se actualicen las estadísticas existentes.

Reflexiones finales

La importación masiva de datos puede no ocurrir todos los días para una aplicación de base de datos, pero hay un impacto en el rendimiento de las consultas cuando se ejecuta. Por eso es necesario minimizar al máximo el tiempo de carga. Una cosa que los DBA pueden hacer para minimizar cualquier sorpresa es probar las optimizaciones de carga en un entorno de desarrollo o ensayo con especificaciones de servidor y configuraciones de PostgreSQL similares. Cada escenario de carga de datos es diferente y es mejor probar cada método y encontrar el que funcione.