POSTGRESQL
#postgresql#explain#optimization#performance#index

PostgreSQL: EXPLAIN ANALYZE — как найти медленный запрос

Как включить и читать план выполнения запроса: EXPLAIN ANALYZE, BUFFERS, Seq Scan vs Index Scan. По официальной документации PostgreSQL.

Как использовать

  1. Перед своим запросом выполни: EXPLAIN (ANALYZE, BUFFERS) SELECT ...
  2. Seq Scan по большой таблице — добавь индекс по полям в WHERE/ORDER BY.
  3. Если rows и actual rows сильно расходятся — выполни ANALYZE table_name;

Поиск узких мест в запросах через план выполнения. По Using EXPLAIN и EXPLAIN.

EXPLAIN показывает план; EXPLAIN ANALYZE выполняет запрос и добавляет фактические время и число строк.


1. Базовый вызов

EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders WHERE created_at > now() - interval '7 days';
  • ANALYZE — запрос реально выполняется, в выводе появляются actual time, actual rows.
  • BUFFERS — показывается использование shared/hit read (полезно для понимания кэша).

Форматы вывода: TEXT (по умолчанию), JSON, YAML, XML. Для консоли достаточно TEXT.


2. Как читать вывод

Плохо — последовательное сканирование большой таблицы:

Seq Scan on orders  (cost=0.00..1234.00 rows=5000 width=80) (actual time=0.05..89.22 rows=4823 loops=1)
  Filter: (created_at > (now() - '7 days'::interval))
  Rows Removed by Filter: 95177
Planning Time: 0.12 ms
Execution Time: 91.45 ms
  • Seq Scan — чтение всей таблицы.
  • Rows Removed by Filter — сколько строк отброшено; при большом числе запрос тяжёлый.

Хорошо — использование индекса:

Index Scan using idx_orders_created_at on orders  (cost=0.42..312.18 rows=5000 width=80) (actual time=0.03..8.11 rows=4823 loops=1)
  Index Cond: (created_at > (now() - '7 days'::interval))
Planning Time: 0.08 ms
Execution Time: 9.02 ms
  • Index Scan — планёр использует индекс; время выполнения обычно сильно меньше.

3. Что делать по результату

СитуацияДействие
Seq Scan по большой таблицеДобавить индекс по полям в WHERE / ORDER BY
rows в плане сильно ≠ actual rowsВыполнить ANALYZE table_name;
Нужна только статистика, без выполненияИспользовать EXPLAIN без ANALYZE

Пример индекса по дате:

CREATE INDEX idx_orders_created_at ON orders(created_at);

После создания индекса снова выполни EXPLAIN (ANALYZE, BUFFERS) SELECT ... и сравни Execution Time.


4. Минимальный рабочий пример

-- Запрос, который хочешь проверить
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, total FROM orders WHERE status = 'paid' ORDER BY created_at DESC LIMIT 100;

-- Если видишь Seq Scan по orders — добавь индекс, например:
-- CREATE INDEX idx_orders_status_created ON orders(status, created_at DESC);
-- Затем снова EXPLAIN (ANALYZE, BUFFERS) ...

Документация: