Материалы / Технические статьи / Партицированные таблицы в EXPLAIN
Статья

Партицированные таблицы в EXPLAIN

Как Append показывает работу с партициями, почему нужен partition pruning и что происходит без фильтра по ключу партиционирования.

Лена подошла к столу Макса с новым планом. На этот раз её вид был озадаченным.

— Макс, я смотрю на запрос к нашей таблице events. И план выглядит… как-то странно. Тут появился узел Append, под которым куча Index Scan по разным таблицам. Это нормально?

Макс взглянул на план:

Append (...)
-> Index Scan using idx_events_2025_08_dt on events_2025_08 ...
-> Index Scan using idx_events_2025_09_dt on events_2025_09 ...

— Поздравляю! — улыбнулся он. — Ты столкнулась с тем, как EXPLAIN показывает работу с партицированными таблицами. Это очень хитро устроенная таблица, которая на самом деле состоит из множества разных таблиц. Узел Append в плане это склейка результатов из релевантных партиций. Каких именно — видно по дочерним узлам.

— Я читала об этом, это похоже на шкаф с одинаковыми документами, где каждый ящик — отдельный месяц?

— Отличная аналогия! — кивнул Макс. — И самая главная магия оптимизатора здесь — это отсечение партиций. При правильном запросе Postgres заранее знает, в какие ящики ему нужно заглянуть, а какие можно проигнорировать. Это и есть ключ к производительности.

Макс открыл два примера, чтобы показать разницу.

  1. “Правильный” запрос с фильтром по ключу партицирования
EXPLAIN SELECT * FROM events WHERE event_date >= '2025-08-15';

В плане будет узел Append, но под ним сканируются только те партиции (ящики), которые содержат нужные даты. Например, events_2025_08, events_2025_09 и так далее. Postgres “отсёк” все партиции за июль и более ранние, даже не заглядывая в них. Это называется partition pruning.

  1. “Неправильный” запрос, который всё портит

— А теперь смотри, — Макс поменял запрос, — если не использовать ключ партицирования в запросе, ну или использовать его не напрямую.

EXPLAIN SELECT * FROM events WHERE date_trunc('month', event_date) = '2025-08-01';

Лена нахмурилась:

— План изменился! Теперь под Append сканируются все партиции с 2022 года!

— Именно! — подтвердил Макс. — И это уже плохо для производительности.

— Получается, главный секрет — помочь Postgres понять, какие партиции ему нужны? — спросила Лена.

— Точно!

— А что если мне нужно выбрать все события пользователя? — спросила Лена. — Например: WHERE user_id = 5.

Макс показал ей план:

Append (...)
-> Index Scan using idx_events_2022_01_user_id on events_2022_01 ...
-> Index Scan using idx_events_2022_02_user_id on events_2022_02 ...
-> ...
-> Index Scan using idx_events_2025_10_user_id on events_2025_10 ...

— Видишь? — пояснил Макс. — Ключ партиционирования — event_date, а фильтр по нему отсутствует. Значит, отсечение партиций не сработает, и Postgres вынужден проходить по каждой партиции отдельно: для каждой — свой Index Scan, а затем результаты «склеиваются» узлом Append. Иногда это будет Parallel Append (если включён параллелизм) или Merge Append при ORDER BY, но суть та же — много мелких сканов вместо одного большого.

— То есть партиции могут даже замедлять? — уточнила Лена.

— Могут, если часто нужен поиск по всем партициям без фильтра по ключу. Лучше сузить диапазон по event_date (например, последние 90 дней), чтобы отсеять лишние партиции. Но выбор схемы партиционирования и вообще «партиционировать или нет» — это отдельная тема.

Что запомнить

  • Фильтр, который совместим с границами партиций, позволяет отсечь лишние дочерние таблицы. Без подходящего условия планировщику обычно приходится рассматривать их все.

  • Следи за функциями над ключом. Если выражение мешает сопоставить условие с границами партиций, перепиши его как диапазон по самому ключу.

  • Проверяй план через EXPLAIN: смотри, какие партиции остались под Append, и поле Subplans Removed, если отсечение произошло во время инициализации плана. Все дочерние таблицы в фактической части плана — повод проверить условие и настройки enable_partition_pruning.

Лена задумчиво кивнула:

— Значит, партицирование — это инструмент, который требует правильного обращения. И EXPLAIN — лучший способ проверить, правильно ли ты его используешь.

— В точку! — подытожил Макс. — Теперь ты знаешь, что Append в плане — это твой друг, который показывает, насколько эффективен твой запрос.