Necesito insertar programáticamente 10 de millones de registros en una base de datos postgres. Actualmente estoy ejecutando miles de declaraciones de inserción en una sola "consulta".
¿Hay una mejor manera de hacer esto, alguna declaración de inserción masiva que no conozca?
postgresql
bulkinsert
Ceniza
fuente
fuente
Existe una alternativa al uso de COPY, que es la sintaxis de valores de varias filas que admite Postgres. De la documentación :
El código anterior inserta dos filas, pero puede extenderlo arbitrariamente, hasta alcanzar el número máximo de tokens de declaración preparados (puede ser $ 999, pero no estoy 100% seguro de eso). A veces no se puede usar COPY, y este es un reemplazo digno para esas situaciones.
fuente
Una forma de acelerar las cosas es realizar explícitamente múltiples inserciones o copias dentro de una transacción (digamos 1000). El comportamiento predeterminado de Postgres es confirmar después de cada declaración, por lo que al agrupar las confirmaciones, puede evitar algunos gastos generales. Como dice la guía en la respuesta de Daniel, es posible que deba desactivar la confirmación automática para que esto funcione. También tenga en cuenta que el comentario en la parte inferior que sugiere aumentar el tamaño de wal_buffers a 16 MB también puede ayudar.
fuente
UNNEST
La función con matrices se puede utilizar junto con la sintaxis VALORES de varias filas. Creo que este método es más lento que el uso,COPY
pero es útil para mí en el trabajo con psycopg y python (pythonlist
pasado a secursor.execute
convierte en pgARRAY
):sin
VALUES
usar subseleccionar con verificación de existencia adicional:la misma sintaxis para las actualizaciones masivas:
fuente
Puede usar el
COPY table TO ... WITH BINARY
cual es " algo más rápido que los formatos de texto y CSV ". Solo haga esto si tiene millones de filas para insertar y si se siente cómodo con los datos binarios.Aquí hay una receta de ejemplo en Python, usando psycopg2 con entrada binaria .
fuente
Depende principalmente de la (otra) actividad en la base de datos. Operaciones como esta congelan efectivamente toda la base de datos para otras sesiones. Otra consideración es el modelo de datos y la presencia de restricciones, disparadores, etc.
Mi primer enfoque es siempre: crear una tabla (temp) con una estructura similar a la tabla de destino (crear la tabla tmp AS select * from target donde 1 = 0), y comenzar leyendo el archivo en la tabla temporal. Luego verifico lo que se puede verificar: duplicados, claves que ya existen en el objetivo, etc.
Luego solo hago un "do insert en target select * from tmp" o similar.
Si esto falla o toma demasiado tiempo, lo aborto y considero otros métodos (descartar temporalmente índices / restricciones, etc.)
fuente
Implementé un cargador de datos Postgresq muy rápido con métodos nativos de libpq. Pruebe mi paquete https://www.nuget.org/packages/NpgsqlBulkCopy/
fuente
Acabo de encontrar este problema y recomendaría csvsql ( lanzamientos ) para importaciones masivas a Postgres. Para realizar una inserción masiva, simplemente
createdb
usaría y luego usaríacsvsql
, que se conecta a su base de datos y crea tablas individuales para una carpeta completa de CSV.fuente
El archivo externo es el mejor y típico de datos masivos.
El término "datos masivos" está relacionado con "una gran cantidad de datos", por lo que es natural utilizar datos originales sin procesar , sin necesidad de transformarlos en SQL. Los archivos de datos en bruto típicos para "inserción masiva" son CSV y JSON formatos .
Inserción masiva con alguna transformación
En aplicaciones ETL y procesos de ingestión, necesitamos cambiar los datos antes de insertarlos. La tabla temporal consume (mucho) espacio en disco, y no es la forma más rápida de hacerlo. El contenedor de datos foráneos PostgreSQL (FDW) es la mejor opción.
Ejemplo de CSV . Supongamos que
tablename (x, y, z)
en SQL y un archivo CSV comoPuede usar el SQL clásico
COPY
para cargar ( como son los datos originales)tmp_tablename
, insertar datos filtrados entablename
... Pero, para evitar el consumo de disco, lo mejor es ingerir directamente porDebe preparar la base de datos para FDW y, en su lugar, estática
tmp_tablename_fdw
, puede usar una función que la genere :JSON ejemplo . Un conjunto de dos archivos,
myRawData1.json
yRanger_Policies2.json
puede ser ingerido por:donde la función jsonb_read_files () lee todos los archivos de una carpeta, definida por una máscara:
Falta de transmisión de gzip
El método más frecuente para la "ingestión de archivos" (principalmente en Big Data) es preservar el archivo original en formato gzip y transferirlo con un algoritmo de transmisión , cualquier cosa que pueda ejecutarse rápidamente y sin consumo de disco en tuberías Unix:
Así que ideal (futuro) es una opción de servidor para el formato
.csv.gz
.fuente