Как бы вы проверили, требуется ли вашему экземпляру БД postgresql больше оперативной памяти для обработки текущих рабочих данных?
Как бы вы проверили, требуется ли вашему экземпляру БД postgresql больше оперативной памяти для обработки текущих рабочих данных?
Ответы:
Если все вы работаете в Linux, ваш общий физический объем ОЗУ должен быть больше размера базы данных на диске, чтобы минимизировать количество операций ввода-вывода. В конце концов, вся база данных будет находиться в кэше чтения ОС, и ввод-вывод будет ограничен фиксацией изменений на диске. Я предпочитаю определять размер БД, запустив "du -shc $ PGDATA / base" - этот метод объединяет все базы данных в одно число. Пока вы крупнее, это должно быть хорошо.
Кроме того, вы можете посмотреть на частоту попаданий в кэш и выборки блоков индекса. Они измеряют частоту попаданий в общие буферы PostgreSQL. Числа могут немного вводить в заблуждение - даже если это может быть ошибка в кеше общих буферов, это все равно может быть попаданием в кэш чтения ОС. Тем не менее, попадания в общие буферы все же обходятся дешевле, чем попадания в кэш чтения ОС (что, в свою очередь, обходится на пару порядков дешевле, чем возврат на диск).
Для того, чтобы посмотреть на частоту попадания в общие буферы, я использую этот запрос:
SELECT relname, heap_blks_read, heap_blks_hit,
round(heap_blks_hit::numeric/(heap_blks_hit + heap_blks_read),3)
FROM pg_statio_user_tables
WHERE heap_blks_read > 0
ORDER BY 4
LIMIT 25;
Это дает вам 25 худших нарушителей, где буферный кеш пропущен для всех таблиц, где по крайней мере один блок должен был быть извлечен с «диска» (опять же, это может быть либо кэш чтения ОС, либо фактический дисковый ввод-вывод). Вы можете увеличить значение в предложении WHERE или добавить другое условие для heap_blks_hit, чтобы отфильтровать редко используемые таблицы.
Тот же базовый запрос можно использовать для проверки общего показателя совпадения индекса для каждой таблицы путем глобальной замены строки «куча» на «idx». Взгляните на pg_statio_user_indexes, чтобы получить разбивку по индексам.
Небольшое примечание об общих буферах: для этого в Linux рекомендуется использовать параметр конфигурации shared_buffers равным 1/4 ОЗУ, но не более 8 ГБ. Это не жесткое правило, а скорее хорошая отправная точка для настройки сервера. Если размер вашей базы данных составляет всего 4 ГБ, а у вас есть сервер 32 ГБ, 8 ГБ общих буферов фактически излишни, и вы должны иметь возможность установить это значение на 5 или 6 ГБ и при этом иметь место для будущего роста.
Я сделал этот SQL, чтобы показать соотношение таблиц к числу обращений к диску:
-- perform a "select pg_stat_reset();" when you want to reset counter statistics
with
all_tables as
(
SELECT *
FROM (
SELECT 'all'::text as table_name,
sum( (coalesce(heap_blks_read,0) + coalesce(idx_blks_read,0) + coalesce(toast_blks_read,0) + coalesce(tidx_blks_read,0)) ) as from_disk,
sum( (coalesce(heap_blks_hit,0) + coalesce(idx_blks_hit,0) + coalesce(toast_blks_hit,0) + coalesce(tidx_blks_hit,0)) ) as from_cache
FROM pg_statio_all_tables --> change to pg_statio_USER_tables if you want to check only user tables (excluding postgres's own tables)
) a
WHERE (from_disk + from_cache) > 0 -- discard tables without hits
),
tables as
(
SELECT *
FROM (
SELECT relname as table_name,
( (coalesce(heap_blks_read,0) + coalesce(idx_blks_read,0) + coalesce(toast_blks_read,0) + coalesce(tidx_blks_read,0)) ) as from_disk,
( (coalesce(heap_blks_hit,0) + coalesce(idx_blks_hit,0) + coalesce(toast_blks_hit,0) + coalesce(tidx_blks_hit,0)) ) as from_cache
FROM pg_statio_all_tables --> change to pg_statio_USER_tables if you want to check only user tables (excluding postgres's own tables)
) a
WHERE (from_disk + from_cache) > 0 -- discard tables without hits
)
SELECT table_name as "table name",
from_disk as "disk hits",
round((from_disk::numeric / (from_disk + from_cache)::numeric)*100.0,2) as "% disk hits",
round((from_cache::numeric / (from_disk + from_cache)::numeric)*100.0,2) as "% cache hits",
(from_disk + from_cache) as "total hits"
FROM (SELECT * FROM all_tables UNION ALL SELECT * FROM tables) a
ORDER BY (case when table_name = 'all' then 0 else 1 end), from_disk desc