Производительность кэша (памяти) Postgresql + способ разогрева кеша

У меня есть таблица DB с 25-миллиметровыми строками, ~ 3K каждый (т.е. ~ 75 ГБ), что вместе с несколькими индексами, которые я использую (дополнительные 15-20 ГБ), не будет полностью помещаться в памяти (64 ГБ на машине). Типичный запрос содержит 300 строк через индекс, при необходимости отфильтровывая их до ~ 50-300 строк с использованием других индексов, и, наконец, извлекает соответствующие строки. Время отклика варьируется от 20 мс на теплой БД до 20 с на холодном БД. У меня есть два связанных вопроса:

  • В любой момент времени я могу проверить, какая часть (%) конкретных таблиц и индексов кэшируется в памяти?

  • Каков наилучший способ разогреть кеш, прежде чем открывать БД для запросов? Например. "select *" принудительно выполняет последовательное сканирование (~ 15 минут на холодном БД), но время ответа после него все еще оставляет желать лучшего. Есть ли встроенный способ сделать это вместо запросов? A

Спасибо, не стесняйтесь также отвечать по электронной почте ([email protected]])

- Шауль

Ответ 1

Что касается вашей первой точки, модуль contrib "pg_buffercache" позволяет вам проверять содержимое буферного кеша. Мне нравится определять это:

create or replace view util.buffercache_hogs as
select case
       when pg_buffercache.reldatabase = 0
            then '- global'
       when pg_buffercache.reldatabase <> (select pg_database.oid from pg_database where pg_database.datname = current_database())
            then '- database ' || quote_literal(pg_database.datname)
       when pg_namespace.nspname = 'pg_catalog'
            then '- system catalogues'
       when pg_class.oid is null and pg_buffercache.relfilenode > 0
            then '- unknown file ' || pg_buffercache.relfilenode
       when pg_namespace.nspname = 'pg_toast' and pg_class.relname ~ '^pg_toast_[0-9]+$'
            then (substring(pg_class.relname, 10)::oid)::regclass || ' TOAST'::text
       when pg_namespace.nspname = 'pg_toast' and pg_class.relname ~ '^pg_toast_[0-9]+_index$'
            then ((rtrim(substring(pg_class.relname, 10), '_index'))::oid)::regclass || ' TOAST index'
       else pg_class.oid::regclass::text
       end as key,
       count(*) as buffers, sum(case when pg_buffercache.isdirty then 1 else 0 end) as dirty_buffers,
       round(count(*) / (SELECT pg_settings.setting FROM pg_settings WHERE pg_settings.name = 'shared_buffers')::numeric, 4) as hog_factor
from pg_buffercache
     left join pg_database on pg_database.oid = pg_buffercache.reldatabase
     left join pg_class on pg_class.relfilenode = pg_buffercache.relfilenode
     left join pg_namespace on pg_namespace.oid = pg_class.relnamespace
group by 1
order by 2 desc;

Кроме того, модуль contribinspect "contrib" позволяет вам получить доступ к определенной странице из отношения, поэтому, я полагаю, вы могли бы просто перебирать все страницы в отношении захвата их?

select count(get_raw_page('information_schema.sql_features', n))
from generate_series(0,
        (select relpages-1 from pg_class where relname = 'sql_features')) n;

Это загрузит все information_schema.sql_features в кеш.

Ответ 2

2) Я обычно решаю это, имея журнал запросов из живой системы и воспроизводя их. Это разогревает типичные части данных, а не те части, которые не так часто используются (что в противном случае было бы потерять ОЗУ).

Ответ 3

Ad. 1 - У меня нет абсолютно никакого идеала.

Ad. 2 - почему бы вам просто не выбрать случайные ответы, которые, как вы знаете, важны, и запустить их на холодном сервере? тем больше будут выполняться запросы, тем лучше будет процесс прогрева.

Ответ 4

Не пытайтесь разогреть память, что работают postgresql и ОС. Просто разделите таблицы (и индексы) на разделы и попробуйте работать с меньшими наборами данных. Если вы создадите хороший план разбиения, тогда нет никаких проблем с огромными индексами или таблицами. Если вы все еще хотите разогреть таблицы и индексы, возможно, их можно будет кэшировать полностью в ОЗУ, поскольку они меньше, чем раньше.