Tengo una instancia de PostgreSQL 9.2 que se ejecuta en RHEL 6.3, máquina de 8 núcleos con 16 GB de RAM. El servidor está dedicado a esta base de datos. Dado que el postgresql.conf predeterminado es bastante conservador con respecto a la configuración de memoria, pensé que podría ser una buena idea permitir que Postgres use más memoria. Para mi sorpresa, seguir consejos en wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server ralentizó significativamente prácticamente todas las consultas que ejecuto, pero obviamente es más notable en las consultas más complejas.
También intenté ejecutar pgtune que dio la siguiente recomendación con más parámetros ajustados, pero eso no cambió nada. Sugiere shared_buffers de 1/4 de tamaño de RAM que parece estar en línea con los consejos en otros lugares (y en PG wiki en particular).
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
Intenté reindexar toda la base de datos después de cambiar la configuración (usando reindex database
), pero eso tampoco ayudó. Jugué con shared_buffers y work_mem. Cambiarlos gradualmente de los valores predeterminados muy conservadores (128k / 1MB) disminuyó gradualmente el rendimiento.
Realicé EXPLAIN (ANALYZE,BUFFERS)
algunas consultas y el culpable parece ser que Hash Join es significativamente más lento. No me queda claro por qué.
Para dar un ejemplo específico, tengo la siguiente consulta. Se ejecuta en ~ 2100 ms en la configuración predeterminada y ~ 3300 ms en la configuración con tamaños de búfer aumentados:
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)
para la consulta anterior:
- Búferes predeterminados: http://explain.depesz.com/s/xaHJ
- Buffers más grandes: http://explain.depesz.com/s/Plk
La pregunta es ¿por qué estoy observando un rendimiento disminuido cuando aumento los tamaños de búfer? La máquina definitivamente no se está quedando sin memoria. La asignación si la memoria compartida en el sistema operativo es ( shmmax
y shmall
) se establece en valores muy grandes, eso no debería ser un problema. Tampoco obtengo ningún error en el registro de Postgres. Estoy ejecutando autovacuum en la configuración predeterminada, pero no espero que tenga nada que ver con eso. Todas las consultas se ejecutaron en la misma máquina con unos segundos de diferencia, solo con una configuración modificada (y reiniciando PG).
Editar: acabo de encontrar un hecho particularmente interesante: cuando realizo la misma prueba en mi iMac de mediados de 2010 (OSX 10.7.5) también con Postgres 9.2.1 y 16 GB de RAM, no experimento la desaceleración. Específicamente:
set work_mem='1MB';
select ...; // running time is ~1800 ms
set work_mem='96MB';
select ...' // running time is ~1500 ms
Cuando hago exactamente la misma consulta (la anterior) con exactamente los mismos datos en el servidor, obtengo 2100 ms con work_mem = 1MB y 3200 ms con 96 MB.
La Mac tiene SSD, por lo que es comprensiblemente más rápido, pero muestra un comportamiento que esperaría.
Consulte también la discusión de seguimiento sobre pgsql-performance .