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

11

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

SDReyes
источник
8
Не нужно проверять, вам всегда нужно больше оперативной памяти. :)
Алекс Ховански
1
Не вопрос программирования, я голосую, чтобы переместить его в ServerFault.
GManNickG
1
Я не администратор баз данных, но начну с того, что все обычные запросы находятся на грани хеш-соединения, а не вложенного цикла. Вы можете сделать некоторые настройки db config, которые могут повлиять на то, сколько памяти доступно для любого конкретного запроса [проверьте документы или отправьте по электронной почте список рассылки - мое предложение]. Также может быть полезно проверить, достаточно ли у вас ОЗУ для кэширования часто используемых таблиц. Но в конечном итоге, если ваша ВСЯ БД не умещается в ОЗУ, вы можете использовать больше. :)

Ответы:

14

Если все вы работаете в 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 ГБ и при этом иметь место для будущего роста.

Мэтью Вуд
источник
9

Я сделал этот 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

введите описание изображения здесь

Кристиан
источник
1

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

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;
Фелипе
источник