Чтобы узнать план запроса, предварите его командой EXPLAIN:

explain select * from applications;

Seq Scan on applications
  (cost=0.00..359524.33 rows=965633 width=1745)

Эта команда НЕ выполнит запрос, а только вернет его план и приблизительные оценки.

План представляет дерево узлов; вложенность определяется пробелами слева. План читают от вложенных узлов к корню. Графические программы вроде PGAdmin показывают его в виде графа. У каждого узла как минимум три характеристики: стоимость (cost), число записей (rows) и средняя длина строки (width).

Стоимость (cost) – это условные попугаи, в которых измеряется каждая операция. С помощью глобальных настроек можно задать свою стоимость некоторым операциям, но обычно это ни к чему. Кроме того, стоимость можно задать функциям при их объявлении.

Число записей (rows) – ожидаемое число записей, которые произведет узел. Для них рассчитана средняя длина в байтах. Эти числа берутся из статистики и могут быть неточны.

Стоимость выражается двумя цифрами: X..Y. Первая цифра – столько усилий уйдет на то, чтобы произвести первую запись. Вторая – последнюю, то есть все остальное.

Зачем две цифры? Дело в том, что даже когда запрос производит много записей, важно знать, сколько усилий требует предварительная работа. Например, у обхода большой таблицы первый кост маленький, а второй – большой. Это нормально, потому что записи передаются следующему узлу без задержки. Если же добавить группировку, то следующий узел не получит данные, пока не выполнится группировка. Из-за этого первый кост будет большим. В идеале нужно держать его маленьким, чтобы клиент сразу начал получать строки.

У команды explain много параметров, чтобы собрать дополнительные метрики узлов. Например, время в секундах, число прочитанных страниц, попадание в буферный кэш. Самый важный параметр называется ANALYZE. С ним запрос будет выполнен, и метрики будут реальными, а не оценочными.

Модуль auto_explain автоматически логирует план запросов, которые выполнялись дольше порога, например одной секунды. Иногда его включают на проде.

Читать план тяжело, этот навык приходит с годами. Вы должны точно понимать, какую информацию ищете и почему ее там нет. В простом случае вас интересует, использовался ли индекс. Вы запускаете explain analyze и смотрите, был ли узел с типом “index scan”.

Узел “index only scan” означает, что данные получены из индекса без обращения к таблице. Это самый жир, лучше которого ничего не бывает. Узел “bitmap index scan” означает построение битовой карты, где каждый бит — номер блока. Такой обход используется для совмещения нескольких индексов, и он тоже хорош.

Узел “full seq scan” означает полный обход таблицы. Это нормально, если таблица мала или нужна ее большая часть. Если вы рассчитывали на индекс, это повод пересмотреть его.