Voir remplir une base de données dans le manuel PostgreSQL, l'excellent article de Depesz sur le sujet, et cette question SO.
(Notez que cette réponse concerne le chargement en bloc de données dans une base de données existante ou pour en créer une nouvelle. Si vous êtes intéressé par les performances de restauration de la base de données avec pg_restore
ou psql
exécution de pg_dump
sortie, une grande partie de cela ne s'applique pas depuis pg_dump
et pg_restore
fait déjà des choses comme créer des déclencheurs et des index après avoir terminé une restauration de schéma + données) .
Il y a beaucoup à faire. La solution idéale serait d'importer dans un UNLOGGED
table sans index, puis changez-la en log et ajoutez les index. Malheureusement, dans PostgreSQL 9.4, il n'y a pas de support pour changer les tables de UNLOGGED
à connecté. 9.5 ajoute ALTER TABLE ... SET LOGGED
pour vous permettre de le faire.
Si vous pouvez mettre votre base de données hors ligne pour l'importation en masse, utilisez pg_bulkload
.
Sinon :
-
Désactiver tous les déclencheurs sur la table
-
Supprimez les index avant de commencer l'import, recréez-les ensuite. (Cela prend beaucoup moins de temps pour construire un index en une seule passe que pour y ajouter progressivement les mêmes données, et l'index résultant est beaucoup plus compact).
-
Si vous effectuez l'importation dans une seule transaction, vous pouvez supprimer en toute sécurité les contraintes de clé étrangère, effectuer l'importation et recréer les contraintes avant de valider. Ne le faites pas si l'importation est répartie sur plusieurs transactions, car vous pourriez introduire des données non valides.
-
Si possible, utilisez
COPY
au lieu deINSERT
s -
Si vous ne pouvez pas utiliser
COPY
pensez à utiliserINSERT
à valeurs multiples s si pratique. Vous semblez déjà le faire. N'essayez pas de lister trop plusieurs valeurs dans un seulVALUES
mais; ces valeurs doivent tenir en mémoire plusieurs fois, alors limitez-vous à quelques centaines par instruction. -
Regroupez vos insertions dans des transactions explicites, en effectuant des centaines de milliers ou des millions d'insertions par transaction. Il n'y a pas de limite pratique AFAIK, mais le traitement par lots vous permettra de récupérer d'une erreur en marquant le début de chaque lot dans vos données d'entrée. Encore une fois, vous semblez déjà le faire.
-
Utilisez
synchronous_commit=off
et un énormecommit_delay
pour réduire les coûts de fsync(). Cependant, cela ne vous aidera pas beaucoup si vous avez regroupé votre travail dans de grosses transactions. -
INSERT
ouCOPY
en parallèle à partir de plusieurs connexions. Le nombre dépend du sous-système de disque de votre matériel ; en règle générale, vous souhaitez une connexion par disque dur physique si vous utilisez un stockage à connexion directe. -
Définir un
max_wal_size
élevé valeur (checkpoint_segments
dans les anciennes versions) et activezlog_checkpoints
. Consultez les journaux PostgreSQL et assurez-vous qu'il ne se plaint pas de points de contrôle trop fréquents. -
Si et seulement si cela ne vous dérange pas de perdre tout votre cluster PostgreSQL (votre base de données et tous les autres sur le même cluster) à cause d'une corruption catastrophique si le système plante pendant l'importation, vous pouvez arrêter Pg, définir
fsync=off
, démarrez Pg, effectuez votre importation, puis arrêtez (essentiellement) Pg et définissezfsync=on
de nouveau. Voir la configuration WAL. Ne le faites pas s'il existe déjà des données qui vous intéressent dans une base de données de votre installation PostgreSQL. Si vous définissezfsync=off
vous pouvez également définirfull_page_writes=off
; encore une fois, n'oubliez pas de le réactiver après votre importation pour éviter la corruption de la base de données et la perte de données. Voir les réglages non durables dans le manuel Pg.
Vous devriez également envisager de régler votre système :
-
Utilisez une bonne qualité SSD pour le stockage autant que possible. De bons SSD avec des caches en écriture fiables et protégés de l'alimentation rendent les taux de validation incroyablement plus rapides. Ils sont moins avantageux lorsque vous suivez les conseils ci-dessus - ce qui réduit les vidages de disque / le nombre de
fsync()
s - mais peut toujours être d'une grande aide. N'utilisez pas de SSD bon marché sans une protection adéquate contre les pannes de courant, sauf si vous ne vous souciez pas de conserver vos données. -
Si vous utilisez RAID 5 ou RAID 6 pour le stockage à connexion directe, arrêtez maintenant. Sauvegardez vos données, restructurez votre matrice RAID en RAID 10 et réessayez. Les RAID 5/6 sont sans espoir pour les performances d'écriture en bloc - bien qu'un bon contrôleur RAID avec un grand cache puisse aider.
-
Si vous avez la possibilité d'utiliser un contrôleur RAID matériel avec un grand cache en écriture sauvegardé par batterie, cela peut vraiment améliorer les performances d'écriture pour les charges de travail avec beaucoup de validations. Cela n'aide pas autant si vous utilisez une validation asynchrone avec un commit_delay ou si vous effectuez moins de transactions volumineuses lors du chargement en masse.
-
Si possible, stockez WAL (
pg_wal
, oupg_xlog
dans les anciennes versions) sur un disque / réseau de disques séparé. Il ne sert à rien d'utiliser un système de fichiers séparé sur le même disque. Les gens choisissent souvent d'utiliser une paire RAID1 pour WAL. Encore une fois, cela a plus d'effet sur les systèmes avec des taux de validation élevés, et cela a peu d'effet si vous utilisez une table non enregistrée comme cible de chargement des données.
Vous pourriez également être intéressé par Optimiser PostgreSQL pour des tests rapides.