Как найти самые "горячие" запросы на вашем PostgreSQL-сервере? Поискать их в логе и проанализировать план или воспользоваться расширением pg_stat_statements. А если в лог попадает миллион запросов за сутки?.. Тогда любое значение лимита pg_stat_statements.max окажется недостаточно велико, чтобы собрать правдивую статистику. Так давайте собирать эту статистику прямо с планов! Но для некоторых сервисов СБИС нам в "Тензоре" производительность запросов к базе настолько важна, что auto_explain.log_min_duration приходится выставлять в единицы миллисекунд - и вот они, миллионы планов... Как не потеряться в них? Давайте сначала проведем небольшой эксперимент на таблице с сильно неоднородными данными: Посмотрим на план одного и того же запроса при v = 0: ... v = 1: ... v = 2: и v = 3, наконец: Если очистить каждый из этих планов от "переменной" информации вроде количества прочитанных данных или времени обработки, останется только "шаблон" плана - текстовое представление алгоритма выполнения запроса: Ровно это делает и наш сервис визуализации планов, когда помогает вам анализировать запрос: Такая методика позволяет миллионы планов превращать в сотни шаблонов. Но подождите, у нас был один и тот же запрос "на входе", а "на выходе" мы получили аж 3 разных шаблона! И если мы будем смотреть сводную статистику по "топовым" шаблонам, то наверняка упустим этот запрос, ведь его показатели будут "размазаны" по нескольким записям. Но ведь, во всех шаблонах мы видим, что производилось сканирование таблицы tst, только разными способами: Seq Scan, Bitmap Scan и Index Scan - и это лишь одна из причин "разбегания" шаблонов, а их много больше: порядок и вид соединения таблиц (Nested Loop, Hash Semi Join, Merge Join, ...) наличие/отсутствие/несовпадение алиасов у одних и тех же таблиц разные виды чтений (Index Only Scan / Index Scan / Bitmap Index Scan) по индексам одной и той же таблицы использование параллелизации при извлечении данных (Seq Scan vs Parallel Seq Scan) наличие/отсутствие вспомогательной сортировки / группировки / уникализации для WindowAgg сработка и порядок триггеров, особенно условных Давайте попробуем получить из шаблона некоторую модель плана, в которую попадали бы (с большой вероятностью) все планы от одного запроса: сохраняем общую структуру плана (CTE / InitPlan / SubPlan / Append) объединяем разные операции над таблицей в Scan Table вместо множества вложенных Join/Loop-узлов, включая сортировки и хэширование, оставляем один Join со отсортированным списком участвующих таблиц дополнительные узлы обработки данных вроде сортировки, группировки и уникализации превращаем в общий узел Process И если все эти преобразования провести над нашими шаблонами, мы получим для них единую модель: Ее можно увидеть на соответствующей вкладке анализа плана. При этом план с достаточно сложной структурой: ... может превратиться во вполне компактное представление: Сотни шаблонов уже превращаются в десятки моделей. Но сами модели могут все-таки немного отличаться друг от друга для "родственных" запросов. Что-то вроде этого: Как определить метрику "похожести" двух моделей? Можно, конечно, подключить какую-то зубодробительную математику, нейронные сети, суперкомпьютеры... А можно подойти алгоритмически и выделить у обеих моделей построчно общий префикс A . Тогда полные модели B и C можно считать его потомками и собрать так иерархию представления для всех моделей сервера. Теперь просто визуализируем размер узла в такой иерархии пропорционально общей статистике модели, и поиск нужной иголки в этом стоге сена уже не будет представлять большой проблемы: Архитектура ИС: PostgreSQL, Node.js и highload