Mam instancję PostgreSQL 9.2 działającą na 8-rdzeniowym komputerze RHEL 6.3 z 16 GB pamięci RAM. Serwer jest dedykowany dla tej bazy danych. Biorąc pod uwagę, że domyślny postgresql.conf jest dość konserwatywny w odniesieniu do ustawień pamięci, pomyślałem, że dobrym pomysłem może być zezwolenie Postgresowi na użycie większej ilości pamięci. Ku mojemu zaskoczeniu, postępując zgodnie z radami na wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server znacznie spowolniłem praktycznie każde zapytanie, które wykonuję, ale jest to oczywiście bardziej zauważalne w przypadku bardziej złożonych zapytań.
Próbowałem również uruchomić pgtune, który dał następującą rekomendację z większą ilością dostrojonych parametrów, ale to nic nie zmieniło. Sugeruje wspólne bufory wielkości 1/4 RAM, co wydaje się zgodne z poradami w innych miejscach (w szczególności na wiki PG).
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
Próbowałem ponownie zindeksować całą bazę danych po zmianie ustawień (za pomocą reindex database
), ale to też nie pomogło. Bawiłem się z shared_buffers i work_mem. Stopniowo zmieniając je z bardzo konserwatywnych wartości domyślnych (128 k / 1 MB), stopniowo zmniejszano wydajność.
Uruchomiłem EXPLAIN (ANALYZE,BUFFERS)
kilka zapytań i sprawcą wydaje się być to, że Hash Join jest znacznie wolniejszy. Nie jest dla mnie jasne, dlaczego.
Aby podać konkretny przykład, mam następujące zapytanie. Działa w ~ 2100ms w konfiguracji domyślnej i ~ 3300ms w konfiguracji ze zwiększonymi rozmiarami buforów:
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)
dla powyższego zapytania:
- Domyślne bufory: http://explain.depesz.com/s/xaHJ
- Większe bufory: http://explain.depesz.com/s/Plk
Pytanie brzmi: dlaczego obserwuję zmniejszoną wydajność, gdy zwiększam rozmiary buforów? W urządzeniu na pewno nie brakuje pamięci. Alokacja, jeśli pamięć współdzielona w systemie operacyjnym jest ( shmmax
i shmall
) ustawiona na bardzo duże wartości, nie powinno stanowić problemu. Nie otrzymuję też żadnych błędów w dzienniku Postgres. Używam autovacuum w domyślnej konfiguracji, ale nie oczekuję, że ma to coś wspólnego z tym. Wszystkie zapytania były uruchamiane na tym samym komputerze w odstępie kilku sekund, tylko ze zmienioną konfiguracją (i zrestartowano PG).
Edycja: Właśnie znalazłem jeden szczególnie interesujący fakt: kiedy wykonuję ten sam test na moim komputerze iMac z połowy 2010 roku (OSX 10.7.5) również z Postgres 9.2.1 i 16 GB pamięci RAM, nie odczuwam spowolnienia. Konkretnie:
set work_mem='1MB';
select ...; // running time is ~1800 ms
set work_mem='96MB';
select ...' // running time is ~1500 ms
Kiedy wykonuję dokładnie to samo zapytanie (powyższe) z dokładnie tymi samymi danymi na serwerze, otrzymuję 2100 ms z work_mem = 1 MB i 3200 ms z 96 MB.
Mac ma dysk SSD, więc jest zrozumiale szybszy, ale zachowuje się tak, jakbym się spodziewał.
Zobacz także dalszą dyskusję na temat wydajności pgsql .