Назад | Перейти на главную страницу

Как я могу проверить, нужно ли моей БД больше оперативной памяти?

Как проверить, требуется ли вашему экземпляру базы данных postgresql больше оперативной памяти для обработки текущих рабочих данных?

Если вы все работаете в Linux, ваша общая физическая RAM должна быть больше, чем размер вашей базы данных на диске, чтобы минимизировать ввод-вывод. В конце концов, вся база данных будет в кэше чтения ОС, а операции ввода-вывода будут ограничены фиксацией изменений на диск. Я предпочитаю определять размер БД, выполнив «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, чтобы отфильтровать редко используемые таблицы.

Тот же самый базовый запрос можно использовать для проверки общего коэффициента попадания индекса для каждой таблицы, глобально заменив строку «heap» на «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

Это также работает, как сказано в документе Heroku:

SELECT
    'cache hit rate' AS name,
     sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) AS ratio
FROM pg_statio_user_tables;