У меня есть экземпляр PostgreSQL 9.2, работающий на RHEL 6.3, 8-ядерный компьютер с 16 ГБ ОЗУ. Сервер выделен для этой базы данных. Учитывая, что файл postgresql.conf по умолчанию довольно консервативен в отношении настроек памяти, я подумал, что было бы неплохо разрешить Postgres использовать больше памяти. К моему удивлению, следующий совет на wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server значительно замедлил практически каждый выполняемый мной запрос, но он явно более заметен в более сложных запросах.
Я также попытался запустить pgtune, который дал следующую рекомендацию с более настроенными параметрами, но это ничего не изменило. Он предлагает shared_buffers размером 1/4 ОЗУ, что, по-видимому, согласуется с рекомендациями в других местах (и в частности в 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
Я попытался переиндексировать всю базу данных после изменения настроек (используя reindex database
), но это тоже не помогло. Я играл с shared_buffers и work_mem. Постепенно изменяя их с очень консервативных значений по умолчанию (128 КБ / 1 МБ), постепенно снижается производительность.
Я запустил EXPLAIN (ANALYZE,BUFFERS)
несколько запросов, и виновник, похоже, в том, что Hash Join значительно медленнее. Мне не понятно почему.
Чтобы привести конкретный пример, у меня есть следующий запрос. Он работает ~ 2100 мс в конфигурации по умолчанию и ~ 3300 мс в конфигурации с увеличенным размером буфера:
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)
для запроса выше:
- Буферы по умолчанию: http://explain.depesz.com/s/xaHJ
- Большие буферы: http://explain.depesz.com/s/Plk
Вопрос в том, почему я наблюдаю снижение производительности при увеличении размеров буфера? У машины точно не хватает памяти. Выделение, если для разделяемой памяти в ОС задано ( shmmax
и shmall
) очень большое значение, это не должно быть проблемой. Я не получаю никаких ошибок в журнале Postgres либо. Я использую автовакуум в конфигурации по умолчанию, но не ожидаю, что это как-то связано с этим. Все запросы выполнялись на одной и той же машине с интервалом в несколько секунд, только с измененной конфигурацией (и перезапускали PG).
Изменить: Я только что нашел один особенно интересный факт: когда я выполняю тот же тест на моем iMac в середине 2010 года (OSX 10.7.5) также с Postgres 9.2.1 и 16 ГБ оперативной памяти, я не испытываю замедления. В частности:
set work_mem='1MB';
select ...; // running time is ~1800 ms
set work_mem='96MB';
select ...' // running time is ~1500 ms
Когда я делаю точно такой же запрос (тот, что выше) с точно такими же данными на сервере, я получаю 2100 мс с work_mem = 1 МБ и 3200 мс с 96 МБ.
У Mac есть SSD, так что это понятно быстрее, но он демонстрирует поведение, которое я ожидаю.
Смотрите также последующее обсуждение pgsql-performance .