J'ai une instance de PostgreSQL 9.2 s'exécutant sur RHEL 6.3, une machine à 8 cœurs avec 16 Go de RAM. Le serveur est dédié à cette base de données. Étant donné que le fichier postgresql.conf par défaut est plutôt conservateur en ce qui concerne les paramètres de mémoire, j'ai pensé que ce serait une bonne idée de permettre à Postgres d'utiliser davantage de mémoire. À ma grande surprise, suivre les conseils sur wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server a considérablement ralenti pratiquement toutes les requêtes que je lance, mais il est évidemment plus visible pour les requêtes plus complexes.
J'ai aussi essayé de lancer pgtune, ce qui a donné la recommandation suivante avec plus de paramètres ajustés, mais cela n'a rien changé. Il suggère des shared_buffers de 1/4 de la taille de la RAM, ce qui semble correspondre aux conseils donnés ailleurs (et sur PG wiki en particulier).
default_statistics_target = 50
maintenance_work_mem = 960MB
constraint_exclusion = on
checkpoint_completion_target = 0.9
effective_cache_size = 11GB
work_mem = 96MB
wal_buffers = 8MB
checkpoint_segments = 16
shared_buffers = 3840MB
max_connections = 80
J'ai essayé de réindexer l'ensemble de la base de données après avoir modifié les paramètres (utilisation reindex database
), mais cela n'a pas aidé non plus. J'ai joué avec shared_buffers et work_mem. En les modifiant progressivement à partir des valeurs par défaut très conservatrices (128 Ko / 1 Mo), les performances ont progressivement diminué.
J'ai couru EXPLAIN (ANALYZE,BUFFERS)
sur quelques requêtes et le coupable semble être que Hash Join est nettement plus lent. Ce n'est pas clair pour moi pourquoi.
Pour donner un exemple spécifique, j'ai la requête suivante. Il s'exécute en ~ 2100ms sur la configuration par défaut et ~ 3300ms sur la configuration avec des tailles de mémoire tampon plus grandes:
select count(*) from contest c
left outer join contestparticipant cp on c.id=cp.contestId
left outer join teammember tm on tm.contestparticipantid=cp.id
left outer join staffmember sm on cp.id=sm.contestparticipantid
left outer join person p on p.id=cp.personid
left outer join personinfo pi on pi.id=cp.personinfoid
where pi.lastname like '%b%' or pi.firstname like '%a%';
EXPLAIN (ANALYZE,BUFFERS)
pour la requête ci-dessus:
- Tampons par défaut: http://explain.depesz.com/s/xaHJ
- Tampons plus importants: http://explain.depesz.com/s/Plk
La question qui se pose est de savoir pourquoi la performance diminue lorsque j'augmente la taille de la mémoire tampon. La machine ne manque définitivement pas de mémoire. L'allocation si la mémoire partagée dans le système d'exploitation est ( shmmax
et shmall
) définie sur de très grandes valeurs, cela ne devrait pas poser de problème. Je ne reçois aucune erreur dans le journal Postgres non plus. J'utilise autovacuum dans la configuration par défaut, mais je ne pense pas que cela y soit pour quelque chose. Toutes les requêtes ont été exécutées sur le même ordinateur à quelques secondes d'intervalle, avec une configuration modifiée (et un redémarrage de la PG).
Edit: Je viens de découvrir un fait particulièrement intéressant: lorsque j’effectue le même test sur mon iMac de mi-2010 (OSX 10.7.5) également avec Postgres 9.2.1 et 16 Go de RAM, je n’éprouve pas le ralentissement. Plus précisément:
set work_mem='1MB';
select ...; // running time is ~1800 ms
set work_mem='96MB';
select ...' // running time is ~1500 ms
Lorsque je fais exactement la même requête (celle ci-dessus) avec exactement les mêmes données sur le serveur, je reçois 2100 ms avec work_mem = 1Mo et 3200 ms avec 96 MB.
Le Mac est équipé de disques SSD, donc il est compréhensible de le faire plus rapidement, mais il présente un comportement auquel je m'attendrais.
Voir également la discussion de suivi sur pgsql-performance .