Партиционирование PostgreSQL: чек-лист перед продакшеном
Партиционирование может упростить работу с большой таблицей, но не всегда ускоряет запросы и добавляет забот в схему, миграции и обслуживание. Перед запуском проверьте ключ, границы разделов, индексы и поведение приложения на реальных запросах.

В PostgreSQL 16 партиционирование помогает отделить части большой таблицы — например, данные за разные месяцы — и упростить их удаление или обслуживание. Но если запросы не позволяют отсечь ненужные разделы, а ключ не поддерживает нужные ограничения уникальности, вы получите более сложную схему без ожидаемого выигрыша. Этот чек-лист поможет проверить решение до продакшена.
Сначала проверьте, что партиционирование решает вашу задачу
Партиционирование — не способ автоматически ускорить любую таблицу. Оно особенно уместно, когда таблица действительно велика, запросы регулярно обращаются к определённым диапазонам ключа, а данные можно обслуживать или удалять целыми группами. Например, можно удалить старый раздел с архивными записями вместо пакетного удаления миллионов строк.
До проектирования соберите запросы приложения и ответьте на три вопроса:
- Какие условия чаще всего стоят в фильтрах: дата, регион, тип записи или другой столбец?
- Можно ли включить ключ партиционирования в эти условия и в запросы на запись?
- Какую операцию вы хотите упростить: чтение, удаление старых данных, загрузку или обслуживание индексов?
Если главный сценарий — запрос по идентификатору, а разделение планируется по дате, PostgreSQL может быть вынужден проверять больше разделов, чем вы ожидаете. Проверяйте это на реальных запросах, а не на абстрактном тесте.
Выберите стратегию под ключ и обслуживание
В PostgreSQL 16 декларативное партиционирование поддерживает разделение по диапазону, списку значений и хешу. Универсально лучшего варианта нет: выбор определяет, какие условия смогут отсечь разделы и насколько удобно будет обслуживать данные.
| Стратегия | Подходит, когда | Цена и риск |
|---|---|---|
| По диапазону | Ключ упорядочен: дата, номер или числовой интервал. Удобно разделять данные по времени. | Нужно заранее создавать разделы с непересекающимися границами. Запись вне имеющихся диапазонов завершится ошибкой, если нет подходящего раздела или раздела по умолчанию. |
| По списку | Значения заранее известны: например, отдельные категории или регионы. | Новые значения требуют внимания при добавлении разделов. Стратегия неудобна, если список значений быстро меняется или разрастается. |
| По хешу | Нужно распределить строки по разделам по значению ключа. | Сложнее обслуживать данные по времени или другой последовательности. Само разделение не гарантирует, что нужный запрос будет читать мало разделов. |
Для диапазонов верхняя граница не входит в раздел, а нижняя входит. Это важно при проектировании соседних интервалов: например, границы должны стыковаться без пересечения. До релиза проверьте, что тип ключа, значения и границы совпадают с тем, что фактически передаёт приложение.
Хороший ключ партиционирования не просто делит таблицу на части: он помогает отсечь лишние данные в частых запросах и не мешает писать новые.
Чек-лист перед запуском
- Сверьте ключ с запросами. Проверьте фильтры, сортировки и операции записи приложения. Запустите типичные запросы через EXPLAIN и убедитесь, что план исключает ненужные разделы. Это и есть pruning* — отсечение разделов, которые не могут содержать нужные строки.
- Проверьте границы и покрытие данных. Смоделируйте записи на нижней и верхней границе каждого диапазона, а также значения, для которых ещё нет раздела. Убедитесь, что ни одна дата или категория не выпадает из схемы.
- Продумайте раздел по умолчанию. Он может принять значения, которые не подходят ни одному другому разделу, но способен скрыть ошибку в расписании создания разделов. Перед присоединением нового раздела проверьте, не попали ли в раздел по умолчанию строки из его будущего диапазона: их наличие может помешать операции.
- Проверьте ограничения уникальности. В PostgreSQL 16 уникальное ограничение или первичный ключ на партиционированной таблице должны включать все столбцы ключа партиционирования. Если раньше идентификатор был уникален по всей таблице, добавление к ограничению даты может изменить смысл: одинаковый идентификатор сможет встретиться в разных разделах. Для глобальной уникальности заранее продумайте отдельный механизм.
- Сверьте индексы с нагрузкой. Индекс на родительской партиционированной таблице связан с индексами разделов, но каждый индекс занимает место и добавляет работу при записи. Проверьте, что нужные индексы есть у разделов, включая новые, и что запросы не опираются на индекс, которого нет в фактической схеме.
- Репетируйте миграцию и обслуживание. Оцените, как создаются и присоединяются новые разделы, что происходит при ошибке и как удалить или архивировать старые данные. Для существующей таблицы заранее спланируйте перенос данных и переключение приложения: смена обычной таблицы на партиционированную — это отдельная миграция, а не безрисковое переключение флага.
- Проверьте нагрузочный сценарий. Используйте близкие к продакшену объёмы данных и параллельность. Сравните время выполнения, число просмотренных разделов, чтение блоков и задержку записи до и после. Без одинаковых условий сравнение не покажет, что именно изменилось.
- Подготовьте мониторинг и откат. Следите за запросами, которые читают больше разделов, чем ожидалось, ошибками вставки из-за отсутствующего раздела и задержками операций обслуживания. Зафиксируйте, как вернуть приложение к предыдущей схеме и восстановить данные, если переключение пройдёт неудачно.
*Pruning — исключение разделов из плана запроса, если ограничения по ключу показывают, что в них не может быть нужных строк. Оно зависит от условий запроса и доступной PostgreSQL информации о разделах; одно лишь наличие партиционирования не означает, что отсечение произойдёт.
Что чаще всего ломается
Запрос читает больше разделов, чем ожидалось
Условие запроса может не ограничивать ключ партиционирования. Сверьте план выполнения для конкретных параметров, в том числе для запросов, которые приложение выполняет с подготовленными выражениями. Если отсечение не срабатывает, сначала проверьте сам фильтр и типы сравниваемых значений, а не добавляйте разделы наугад.
Запись не находит подходящий раздел
Для диапазонного или списочного разбиения вставка с неподдержанным значением не попадёт в нужное место автоматически. Проверьте, что приложение и процесс создания разделов согласованы по времени. Раздел по умолчанию может смягчить этот риск, но тогда его нужно регулярно проверять на неожиданные строки.
Ограничение перестало означать то же самое
После изменения первичного ключа или уникального ограничения проверьте не только успешность миграции, но и смысл проверки уникальности. Если ключ включает дату партиционирования, он не обязательно запрещает повтор идентификатора между разными датами. Это может стать ошибкой приложения, даже если сама база принимает данные корректно.
Добавление раздела мешает обслуживанию
Присоединение нового раздела может требовать проверки его границ и содержимого. Если используется раздел по умолчанию, заранее выясните, нет ли там строк, которые должны перейти в новый раздел. Репетируйте операцию на копии данных и учитывайте, что блокировки и длительность зависят от схемы и объёма таблиц.
Когда выбирать каждый подход
Выбирайте диапазоны, если ключ естественно упорядочен и важно обслуживать данные интервалами. Список подходит для небольшого контролируемого набора категорий. Хеш стоит рассматривать, когда нужно распределить строки по значению ключа, а обслуживание по времени не является главным требованием. Если запросы не позволяют отсекать разделы и нет отдельной выгоды от обслуживания частями, сначала проверьте индексы и план запроса на обычной таблице.
Количество и размер разделов подбирайте по измерениям на вашей схеме: универсального числа для всех таблиц нет. Слишком мелкое деление увеличивает количество объектов, которыми нужно управлять, а слишком крупное может не дать ожидаемой выгоды для выборок и обслуживания.
Что делать дальше
Возьмите самые частые запросы и сценарии записи из приложения, затем прогоните их на копии данных с будущей схемой. Сохраните планы выполнения и показатели задержки, проверьте создание, присоединение и удаление раздела, а также вставки на границах. После релиза отдельно наблюдайте за отсечением разделов, ошибками записи и временем операций обслуживания: именно они покажут, работает ли выбранная схема в продакшене.
Тендерный специалист 44-ФЗ / 223-ФЗ: Разбор PDF-документации закупки, поиск «заточек» под поставщика, чек-лист заявки.
Спросить за 20 ₽Источники: PostgreSQL 16: декларативное партиционирование, PostgreSQL 16: параметры планирования запросов
Частые вопросы
Партиционирование обязательно ускорит запросы?
Можно ли сохранить глобальную уникальность идентификатора?
Что будет, если для новой записи ещё нет раздела?
Стоит ли всегда создавать раздел по умолчанию?
Как понять, что PostgreSQL действительно отсекает разделы?
Эти рекомендации подходят для PostgreSQL 17 или более новых версий?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.