PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment accélérer les performances d'insertion dans PostgreSQL

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 de INSERT s

  • Si vous ne pouvez pas utiliser COPY pensez à utiliser INSERT à valeurs multiples s si pratique. Vous semblez déjà le faire. N'essayez pas de lister trop plusieurs valeurs dans un seul VALUES 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 énorme commit_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 ou COPY 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 activez log_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éfinissez fsync=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éfinissez fsync=off vous pouvez également définir full_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 , ou pg_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.