До десятой версии PostgreSQL партиционирование собирали вручную через наследование таблиц и триггеры на INSERT — рабочая, но хрупкая конструкция, которую легко сломать неосторожным DDL. Декларативное партиционирование сделало то же самое штатным синтаксисом: секции объявляются прямо при создании таблицы, а планировщик сам знает о структуре и использует её при построении плана запроса.
Синтаксис для диапазонов по дате — обычное дело для таблиц с логами или метриками:
CREATE TABLE measurement (
city_id int NOT NULL,
logdate date NOT NULL,
peaktemp int,
unitsales int
) PARTITION BY RANGE (logdate);
CREATE TABLE measurement_y2026m10 PARTITION OF measurement
FOR VALUES FROM ('2026-10-01') TO ('2026-11-01');
Для PARTITION BY LIST значения перечисляются явно, что удобно для партиционирования по региону или арендатору (tenant) в мультитенантной схеме:
CREATE TABLE cities_ab PARTITION OF cities
FOR VALUES IN ('a', 'b');
Каждая секция — полноценная таблица на диске, поэтому старые месяцы или годы можно выводить из оборота без единого DELETE. DETACH PARTITION отвязывает секцию от родителя, оставляя её отдельной таблицей (под переименование и архивацию), а DROP TABLE на самой секции удаляет миллионы строк за миллисекунды, потому что физически это просто удаление файла, а не построчная чистка с записью в WAL:
ALTER TABLE measurement DETACH PARTITION measurement_y2006m02 CONCURRENTLY;
DROP TABLE measurement_y2006m02;
CONCURRENTLY у DETACH (с 14-й версии) берёт SHARE UPDATE EXCLUSIVE вместо ACCESS EXCLUSIVE — обычные запросы к родительской таблице не блокируются на время операции, что критично на таблице, которая не прекращает принимать новые вставки.
Главная причина так усложнять DDL — не организация данных, а partition pruning: при запросе с условием на logdate планировщик доказывает, какие секции заведомо не содержат подходящих строк, и исключает их из плана ещё до выполнения. На таблице с двумя-тремя годами ежедневных партиций это разница между сканированием одной секции за сегодня и полным проходом по всей истории. Включено по умолчанию (enable_partition_pruning = on), проверить эффект проще всего через EXPLAIN — в плане просто не будет упоминаний отброшенных секций. Отдельная деталь, о которую часто спотыкаются: PRIMARY KEY/UNIQUE на партиционированной таблице обязаны включать столбец партиционирования — обычный PRIMARY KEY (id) без logdate в списке колонок PostgreSQL просто не даст создать.
#postgresql #dba
