Ho un'istanza PostgreSQL 9.2 in esecuzione su RHEL 6.3, macchina a 8 core con 16 GB di RAM. Il server è dedicato a questo database. Dato che il postgresql.conf predefinito è piuttosto prudente per quanto riguarda le impostazioni di memoria, ho pensato che sarebbe una buona idea consentire a Postgres di usare più memoria. Con mia sorpresa, seguire i consigli su wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server ha notevolmente rallentato praticamente ogni query che eseguo, ma è ovviamente più evidente nelle query più complesse.
Ho anche provato a eseguire pgtune che ha dato la seguente raccomandazione con più parametri sintonizzati, ma ciò non ha cambiato nulla. Suggerisce shared_buffers di 1/4 della dimensione della RAM che sembra in linea con i consigli altrove (e in particolare su PG wiki).
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
Ho provato a reindicizzare l'intero database dopo aver modificato le impostazioni (usando reindex database
), ma neanche questo mi ha aiutato. Ho giocato con shared_buffers e work_mem. Modificandoli gradualmente dai valori predefiniti molto conservativi (128 k / 1 MB), le prestazioni diminuivano gradualmente.
Ho fatto EXPLAIN (ANALYZE,BUFFERS)
alcune domande e il colpevole sembra essere che Hash Join sia significativamente più lento. Non mi è chiaro il perché.
Per fare un esempio specifico, ho la seguente domanda. Funziona in ~ 2100ms sulla configurazione predefinita e ~ 3300ms sulla configurazione con dimensioni del buffer aumentate:
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)
per la query sopra:
- Buffer predefiniti: http://explain.depesz.com/s/xaHJ
- Buffer più grandi: http://explain.depesz.com/s/Plk
La domanda è: perché osservo una riduzione delle prestazioni quando aumento le dimensioni del buffer? La macchina sicuramente non sta esaurendo la memoria. Allocazione se la memoria condivisa nel sistema operativo è ( shmmax
e shmall
) impostata su valori molto grandi, ciò non dovrebbe costituire un problema. Non sto riscontrando errori nemmeno nel registro di Postgres. Sto eseguendo autovacuum nella configurazione predefinita ma non mi aspetto che abbia nulla a che fare con esso. Tutte le query sono state eseguite sulla stessa macchina a pochi secondi di distanza, solo con una configurazione modificata (e riavviato PG).
Modifica: ho appena trovato un fatto particolarmente interessante: quando eseguo lo stesso test sul mio iMac di metà 2010 (OSX 10.7.5) anche con Postgres 9.2.1 e 16 GB di RAM, non avverto il rallentamento. In particolare:
set work_mem='1MB';
select ...; // running time is ~1800 ms
set work_mem='96MB';
select ...' // running time is ~1500 ms
Quando eseguo esattamente la stessa query (quella sopra) con esattamente gli stessi dati sul server, ottengo 2100 ms con work_mem = 1 MB e 3200 ms con 96 MB.
Il Mac ha SSD quindi è comprensibilmente più veloce, ma mostra un comportamento che mi aspetterei.
Vedi anche la discussione di follow-up su pgsql-performance .