J'ai besoin d'insérer par programme des dizaines de millions d'enregistrements dans une base de données PostgreSQL. Actuellement, j'exécute des milliers d'instructions d'insertion dans une seule "requête".
Y a-t-il une meilleure façon de le faire, une instruction d'insertion en masse que je ne connais pas?
postgresql
bulkinsert
Cendre
la source
la source
Il existe une alternative à l'utilisation de COPY, qui est la syntaxe des valeurs à plusieurs lignes prise en charge par Postgres. De la documentation :
Le code ci-dessus insère deux lignes, mais vous pouvez l'étendre arbitrairement, jusqu'à ce que vous atteigniez le nombre maximal de jetons d'instruction préparés (il peut s'agir de 999 $, mais je n'en suis pas sûr à 100%). Parfois, on ne peut pas utiliser COPY, et c'est un remplacement valable pour ces situations.
la source
Une façon d'accélérer les choses consiste à effectuer explicitement plusieurs insertions ou copies dans une transaction (disons 1000). Le comportement par défaut de Postgres est de valider après chaque instruction, donc en regroupant les validations, vous pouvez éviter certains frais généraux. Comme le dit le guide dans la réponse de Daniel, vous devrez peut-être désactiver la validation automatique pour que cela fonctionne. Notez également le commentaire en bas qui suggère d'augmenter la taille des wal_buffers à 16 Mo peut également aider.
la source
UNNEST
La fonction avec des tableaux peut être utilisée avec la syntaxe VALUES à plusieurs lignes. Je pense que cette méthode est plus lente que son utilisation,COPY
mais elle m'est utile dans le travail avec psycopg et python (pythonlist
passé àcursor.execute
devient pgARRAY
):sans
VALUES
utiliser subselect avec contrôle d'existence supplémentaire:la même syntaxe pour les mises à jour groupées:
la source
Vous pouvez utiliser
COPY table TO ... WITH BINARY
ce qui est " un peu plus rapide que les formats texte et CSV ". Ne faites cela que si vous avez des millions de lignes à insérer et si vous êtes à l'aise avec les données binaires.Voici un exemple de recette en Python, utilisant psycopg2 avec une entrée binaire .
la source
Cela dépend principalement de l'activité (autre) dans la base de données. De telles opérations gèlent efficacement la base de données entière pour d'autres sessions. Une autre considération est le modèle de données et la présence de contraintes, de déclencheurs, etc.
Ma première approche est toujours: créer une table (temporaire) avec une structure similaire à la table cible (créer une table tmp AS select * à partir de la cible où 1 = 0), et commencer par lire le fichier dans la table temporaire. Ensuite, je vérifie ce qui peut être vérifié: les doublons, les clés qui existent déjà dans la cible, etc.
Ensuite, je fais juste un "ne insérer dans la cible select * from tmp" ou similaire.
Si cela échoue ou prend trop de temps, je l'abandonne et j'envisage d'autres méthodes (suppression temporaire des index / contraintes, etc.)
la source
J'ai implémenté un chargeur de données Postgresq très rapide avec des méthodes natives libpq. Essayez mon package https://www.nuget.org/packages/NpgsqlBulkCopy/
la source
Je viens de rencontrer ce problème et je recommanderais csvsql ( versions ) pour les importations en vrac vers Postgres. Pour effectuer une insertion en bloc, vous devez simplement
createdb
et ensuite utilisercsvsql
, qui se connecte à votre base de données et crée des tables individuelles pour un dossier entier de CSV.la source
Le fichier externe est le meilleur et typique des données en masse
Le terme «données en masse» est lié à «beaucoup de données», il est donc naturel d'utiliser des données brutes originales , sans avoir besoin de les transformer en SQL. Les fichiers de données brutes typiques pour "insertion en bloc" sont CSV et JSON formats .
Insert en vrac avec une certaine transformation
Dans les applications ETL et les processus d'ingestion, nous devons modifier les données avant de les insérer. La table temporaire consomme (beaucoup) d'espace disque et ce n'est pas le moyen le plus rapide de le faire. Le wrapper de données étrangères (FDW) PostgreSQL est le meilleur choix.
Exemple CSV . Supposons que
tablename (x, y, z)
le SQL et un fichier CSV commeVous pouvez utiliser le SQL classique
COPY
pour charger ( comme les données d'origine) danstmp_tablename
, les insérer des données filtrées danstablename
... Mais, pour éviter la consommation de disque, le mieux est d'ingérer directement parVous devez préparer la base de données pour FDW, et à la place statique,
tmp_tablename_fdw
vous pouvez utiliser une fonction qui la génère :Exemple JSON . Un ensemble de deux fichiers,
myRawData1.json
etRanger_Policies2.json
peut être ingéré par:où la fonction jsonb_read_files () lit tous les fichiers d'un dossier, définis par un masque:
Manque de streaming gzip
La méthode la plus fréquente pour «l'ingestion de fichiers» (principalement dans le Big Data) est de conserver le fichier d'origine au format gzip et de le transférer avec un algorithme de streaming , tout ce qui peut fonctionner rapidement et sans consommation de disque dans les canaux Unix:
Donc, idéal (futur) est une option de serveur pour le formatage
.csv.gz
.la source