Je passe à PostgreSQL depuis SQLite pour une application Rails typique.
Le problème est que l'exécution des spécifications est devenue lente avec PG.
Sur SQLite, cela prenait ~ 34 secondes, sur PG c'est ~ 76 secondes, ce qui est plus de 2x plus lent .
Alors maintenant, je veux appliquer certaines techniques pour amener les performances des spécifications au même niveau que SQLite sans modification de code (idéalement simplement en définissant les options de connexion, ce qui n'est probablement pas possible).
Quelques choses évidentes du haut de ma tête sont:
- Disque RAM (une bonne configuration avec RSpec sur OSX serait bien à voir)
- Tables non journalisées (peut-il être appliqué sur toute la base de données pour que je n'aie pas à changer tous les scripts?)
Comme vous l'avez peut-être compris, je ne me soucie pas de la fiabilité et du reste (la DB n'est qu'un truc jetable ici).
Je dois tirer le meilleur parti de la PG et la rendre aussi rapide que possible .
La meilleure réponse décrirait idéalement les astuces pour faire exactement cela, la configuration et les inconvénients de ces astuces.
MISE À JOUR: fsync = off
+ full_page_writes = off
seulement réduit le temps à ~ 65 secondes (~ -16 secondes). Bon début, mais loin de l'objectif de 34.
MISE À JOUR 2: J'ai essayé d'utiliser un disque RAM mais le gain de performances se situait dans une marge d'erreur. Cela ne semble donc pas en valoir la peine.
MISE À JOUR 3: * J'ai trouvé le plus gros goulot d'étranglement et maintenant mes spécifications fonctionnent aussi vite que celles de SQLite.
Le problème était le nettoyage de la base de données qui a effectué la troncature . Apparemment, SQLite est beaucoup trop rapide là-bas.
Pour le "réparer", j'ouvre une transaction avant chaque test et la restaure à la fin.
Quelques chiffres pour environ 700 tests.
- Troncature: SQLite - 34s, PG - 76s.
- Transaction: SQLite - 17s, PG - 18s.
Augmentation de la vitesse 2x pour SQLite. Augmentation de la vitesse 4x pour PG.
la source
Réponses:
Tout d'abord, utilisez toujours la dernière version de PostgreSQL. Les améliorations des performances sont toujours à venir, donc vous perdez probablement votre temps si vous optimisez une ancienne version. Par exemple, PostgreSQL 9.2 améliore considérablement la vitesse
TRUNCATE
et ajoute bien sûr des analyses d'index uniquement. Même les versions mineures doivent toujours être suivies; voir la politique de version .À ne pas faire
Ne placez PAS d' espace disque logique sur un disque RAM ou tout autre stockage non durable .
Si vous perdez un espace de table, la base de données entière peut être endommagée et difficile à utiliser sans travail important. Il y a très peu d'avantages par rapport à l'utilisation de
UNLOGGED
tables et à beaucoup de RAM pour le cache de toute façon.Si vous voulez vraiment un système basé sur ramdisk,
initdb
un tout nouveau cluster sur le ramdisk eninitdb
créant une nouvelle instance PostgreSQL sur le ramdisk, vous avez donc une instance PostgreSQL complètement jetable.Configuration du serveur PostgreSQL
Lors des tests, vous pouvez configurer votre serveur pour un fonctionnement non durable mais plus rapide .
C'est l'une des seules utilisations acceptables pour le
fsync=off
paramètre dans PostgreSQL. Ce paramètre indique à peu près à PostgreSQL de ne pas se soucier des écritures ordonnées ou de tout autre élément désagréable de protection de l'intégrité des données et de sécurité en cas de crash, ce qui lui permet de supprimer totalement vos données si vous perdez de l'énergie ou avez un crash du système d'exploitation.Inutile de dire que vous ne devez jamais activer
fsync=off
en production à moins que vous n'utilisiez Pg comme base de données temporaire pour des données que vous pouvez recréer ailleurs. Si et seulement si vous faites pour désactiver fsync, vous pouvez également lefull_page_writes
désactiver, car cela ne sert plus à rien. Méfiez-vous de celafsync=off
etfull_page_writes
appliquez-le au niveau du cluster , afin qu'ils affectent toutes les bases de données de votre instance PostgreSQL.Pour une utilisation en production, vous pouvez éventuellement utiliser
synchronous_commit=off
et définir uncommit_delay
, car vous bénéficierez des mêmes avantages quefsync=off
sans le risque de corruption des données géantes. Vous avez une petite fenêtre de perte de données récentes si vous activez la validation asynchrone - mais c'est tout.Si vous avez la possibilité de modifier légèrement la DDL, vous pouvez également utiliser les
UNLOGGED
tables de la Pg 9.1+ pour éviter complètement la journalisation WAL et obtenir une augmentation de vitesse réelle au prix de l'effacement des tables en cas de panne du serveur. Il n'y a pas d'option de configuration pour rendre toutes les tables non enregistrées, elle doit être définie pendantCREATE TABLE
. En plus d'être bon pour les tests, cela est pratique si vous avez des tables remplies de données générées ou non importantes dans une base de données qui contient autrement des éléments dont vous avez besoin pour être en sécurité.Vérifiez vos journaux et voyez si vous recevez des avertissements concernant trop de points de contrôle. Si vous l'êtes, vous devriez augmenter vos checkpoint_segments . Vous pouvez également ajuster votre checkpoint_completion_target pour lisser les écritures.
Ajustez
shared_buffers
pour s'adapter à votre charge de travail. Cela dépend du système d'exploitation, dépend de ce qui se passe avec votre machine et nécessite des essais et des erreurs. Les valeurs par défaut sont extrêmement conservatrices. Vous devrez peut-être augmenter la limite de mémoire partagée maximale du système d'exploitation si vous augmentezshared_buffers
sur PostgreSQL 9.2 et inférieur; 9.3 et au-dessus ont changé la façon dont ils utilisent la mémoire partagée pour éviter cela.Si vous utilisez seulement quelques connexions qui font beaucoup de travail, augmentez leur
work_mem
pour leur donner plus de RAM pour jouer, etc. Attention, unwork_mem
paramètre trop élevé peut provoquer des problèmes de mémoire insuffisante car il n'est pas par tri par connexion, donc une requête peut avoir plusieurs types imbriqués. Vous ne devez vraiment augmenter quework_mem
si vous pouvez voir des tris se répandre sur le disqueEXPLAIN
ou se connecter avec lelog_temp_files
paramètre (recommandé), mais une valeur plus élevée peut également permettre à Pg de choisir des plans plus intelligents.Comme dit par une autre affiche ici, il est sage de mettre le xlog et les tables / index principaux sur des disques durs séparés si possible. Des partitions séparées sont assez inutiles, vous voulez vraiment des disques séparés. Cette séparation présente beaucoup moins d'avantages si vous utilisez
fsync=off
et presque aucune si vous utilisez desUNLOGGED
tables.Enfin, ajustez vos requêtes. Assurez - vous que votre
random_page_cost
etseq_page_cost
reflètent la performance de votre système, assurez -vous de votreeffective_cache_size
est correct, etc. UtilisezEXPLAIN (BUFFERS, ANALYZE)
d'examiner les plans de requête individuels, et tourner leauto_explain
module pour signaler toutes les requêtes lentes. Vous pouvez souvent améliorer considérablement les performances des requêtes simplement en créant un index approprié ou en modifiant les paramètres de coût.AFAIK il n'y a aucun moyen de définir une base de données entière ou un cluster comme
UNLOGGED
. Ce serait intéressant de pouvoir le faire. Pensez à demander sur la liste de diffusion PostgreSQL.Optimisation du système d'exploitation hôte
Vous pouvez également effectuer certains réglages au niveau du système d'exploitation. La principale chose que vous voudrez peut-être faire est de convaincre le système d'exploitation de ne pas vider les écritures sur le disque de manière agressive, car vous ne vous souciez vraiment pas de savoir quand / si elles arrivent sur le disque.
Sous Linux , vous pouvez contrôler cela avec le sous - système de mémoire virtuelle de »
dirty_*
paramètres, commedirty_writeback_centisecs
.Le seul problème avec le réglage des paramètres d'écriture différée est trop lâche, c'est qu'un vidage par un autre programme peut entraîner le vidage de tous les tampons accumulés de PostgreSQL, provoquant de gros blocages pendant que tout bloque sur les écritures. Vous pouvez peut-être atténuer cela en exécutant PostgreSQL sur un autre système de fichiers, mais certaines vidanges peuvent être au niveau de l'appareil ou au niveau de l'hôte entier et non au niveau du système de fichiers, vous ne pouvez donc pas vous fier à cela.
Ce réglage nécessite vraiment de jouer avec les paramètres pour voir ce qui fonctionne le mieux pour votre charge de travail.
Sur les noyaux plus récents, vous pouvez vous assurer qu'il
vm.zone_reclaim_mode
est défini sur zéro, car cela peut entraîner de graves problèmes de performances avec les systèmes NUMA (la plupart des systèmes de nos jours) en raison des interactions avec la gestion de PostgreSQLshared_buffers
.Optimisation des requêtes et de la charge de travail
Ce sont des choses qui nécessitent des changements de code; ils peuvent ne pas vous convenir. Vous pourriez être en mesure d'appliquer certaines choses.
Si vous ne regroupez pas le travail en transactions plus importantes, commencez. Beaucoup de petites transactions sont chères, vous devriez donc grouper des trucs chaque fois que cela est possible et pratique. Si vous utilisez la validation asynchrone, cela est moins important, mais toujours fortement recommandé.
Dans la mesure du possible, utilisez des tables temporaires. Ils ne génèrent pas de trafic WAL, ils sont donc beaucoup plus rapides pour les insertions et les mises à jour. Parfois, cela vaut la peine d'intégrer un tas de données dans une table temporaire, de les manipuler comme vous le souhaitez, puis
INSERT INTO ... SELECT ...
de les copier dans la table finale. Notez que les tables temporaires sont par session; si votre session se termine ou si vous perdez votre connexion, la table temporaire disparaît et aucune autre connexion ne peut voir le contenu des tables temporaires d'une session.Si vous utilisez PostgreSQL 9.1 ou une version plus récente, vous pouvez utiliser des
UNLOGGED
tableaux pour les données que vous pouvez vous permettre de perdre, comme l'état de la session. Ceux-ci sont visibles sur différentes sessions et préservés entre les connexions. Ils sont tronqués si le serveur s'arrête de manière impure, ils ne peuvent donc pas être utilisés pour tout ce que vous ne pouvez pas recréer, mais ils sont parfaits pour les caches, les vues matérialisées, les tables d'état, etc.En général, non
DELETE FROM blah;
. UtilisezTRUNCATE TABLE blah;
plutôt; c'est beaucoup plus rapide lorsque vous videz toutes les lignes d'un tableau. Tronquez plusieurs tables en un seulTRUNCATE
appel si vous le pouvez. Il y a cependant une mise en garde si vous faites beaucoupTRUNCATES
de petites tables encore et encore; voir: Vitesse de troncature PostgresqlSi vous n'avez pas d'index sur les clés étrangères, les
DELETE
s impliquant les clés primaires référencées par ces clés étrangères seront horriblement lentes. Assurez-vous de créer de tels index si vous vous y attendez àDELETE
partir des tables référencées. Les index ne sont pas requis pourTRUNCATE
.Ne créez pas d'index dont vous n'avez pas besoin. Chaque indice a un coût de maintenance. Essayez d'utiliser un ensemble minimal d'index et laissez les analyses d'index bitmap les combiner plutôt que de maintenir trop d'index multicolonnes énormes et coûteux. Lorsque des index sont requis, essayez de remplir d'abord la table, puis créez des index à la fin.
Matériel
Avoir suffisamment de RAM pour contenir la base de données entière est une énorme victoire si vous pouvez la gérer.
Si vous n'avez pas assez de RAM, le stockage le plus rapide est le mieux. Même un SSD bon marché fait une énorme différence par rapport à la rouille en rotation. Ne faites pas confiance aux SSD bon marché pour la production, ils ne sont souvent pas sûrs et peuvent manger vos données.
Apprentissage
Le livre de Greg Smith, PostgreSQL 9.0 High Performance reste pertinent malgré une référence à une version un peu plus ancienne. Ce devrait être une référence utile.
Rejoignez la liste de diffusion générale PostgreSQL et suivez-la.
En train de lire:
la source
Utilisez une disposition de disque différente:
modifications de postgresql.conf:
la source
fsync=off
, mettre pg_xlog sur un disque séparé ne s'améliore plus beaucoup.