Что смотреть в метриках базы при высокой утилизации CPU и что делать
Что проверяют
Умеете ли вы искать причину по данным, а не перебирать догадки. Вопрос любят задавать разработчику на Java, потому что чаще всего процессор базы греет именно приложение: запросы, порождённые ORM, размер пула, отсутствие пагинации.
Как отвечать
Сначала отделите работу от ожидания. Процессор занят, а диск свободен, значит время уходит на вычисления: последовательные сканирования, сортировки, соединения больших наборов, разбор и планирование запросов. Процессор занят на фоне массовых ожиданий блокировок это другая история, и индексами она не лечится.
Дальше смотрите по порядку. В PostgreSQL pg_stat_statements даёт список по суммарному времени и числу вызовов, и виноват почти всегда не самый медленный запрос, а средний, вызываемый тысячи раз. pg_stat_activity показывает, что выполняется сейчас и чего ждёт. pg_stat_user_tables показывает соотношение последовательных сканирований и обращений по индексу. Отдельно проверьте попадание в кеш, создание временных файлов при сортировке, работу автоочистки и распухание таблиц, число соединений относительно числа ядер.
Потом действия. У виновного запроса берём план через EXPLAIN (ANALYZE, BUFFERS), чиним предикат или добавляем индекс, при широкой таблице думаем о частичном и покрывающем. Со стороны приложения ищем выборку по одной строке в цикле, загрузку коллекции целиком, пул больше, чем база способна обслужить, и повторные попытки, которые множат нагрузку.
Где спотыкаются
Начинают с настроек памяти. Крутить параметры вслепую дешевле, чем читать планы, но высокая утилизация почти всегда упирается в конкретный запрос или в их количество.
Считают, что план запроса помогает найти виноватого. План объясняет уже выбранный запрос, а найти его можно только по накопленной статистике или журналу медленных запросов.
Увеличивают пул соединений, когда база задыхается. Больше одновременных сессий, чем ядер, работу не ускоряют, а добавляют переключений контекста и конкуренции за блокировки.