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

↑ 2.1 PostgreSQL: индексы, транзакции, оптимизация · ← Предыдущая · → Следующая

Обязательно~4 мин чтенияУровень: middle

Зачем это на собесе

Партиционирование помогает управлять огромными таблицами; важно знать виды и подводные камни.

Зачем

  • ускорение запросов за счёт partition pruning (читаются только нужные партиции);
  • быстрое удаление старых данных: DROP PARTITION вместо DELETE + VACUUM;
  • меньшие индексы и более эффективное обслуживание (VACUUM по партициям);
  • разделение по хранилищам (tablespace).

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

Виды (декларативное)

ВидКлючПример
RANGEдиапазон значенийпо месяцам
LISTсписок значенийпо региону/тенанту
HASHхэш по модулюравномерное распределение без естественного ключа
CREATE TABLE events (
  id         bigint GENERATED ALWAYS AS IDENTITY,
  created_at timestamptz NOT NULL,
  user_id    bigint NOT NULL,
  payload    jsonb,
  PRIMARY KEY (id, created_at)                -- ключ партиционирования входит в PK
) PARTITION BY RANGE (created_at);
 
CREATE TABLE events_2026_09 PARTITION OF events
  FOR VALUES FROM ('2026-09-01') TO ('2026-10-01');
CREATE TABLE events_default PARTITION OF events DEFAULT;
 
CREATE INDEX ON events (user_id, created_at);   -- создаётся на всех партициях

Особенности

  • уникальные ограничения и PK должны включать ключ партиционирования;
  • внешние ключи на партиционированные таблицы поддерживаются, но ограничения есть;
  • запросы обязаны фильтровать по ключу, иначе просматриваются все партиции;
  • слишком много партиций (тысячи) увеличивает время планирования;
  • есть DEFAULT-партиция: следите, чтобы она не распухала;
  • глобальных индексов нет: индексы локальны для каждой партиции.

Обслуживание

-- отсоединить и удалить старую партицию
ALTER TABLE events DETACH PARTITION events_2025_01 CONCURRENTLY;
DROP TABLE events_2025_01;
 
-- присоединить готовую (сначала CHECK, чтобы не сканировать)
ALTER TABLE events_2026_10 ADD CONSTRAINT c CHECK (created_at >= '2026-10-01' AND created_at < '2026-11-01');
ALTER TABLE events ATTACH PARTITION events_2026_10 FOR VALUES FROM ('2026-10-01') TO ('2026-11-01');

Автоматизация: pg_partman, cron/джобы, создавать партиции заранее.

Проверка pruning

EXPLAIN SELECT * FROM events WHERE created_at >= '2026-09-10' AND created_at < '2026-09-11';
-- в плане только events_2026_09

Работает при константах и параметрах; для нестандартных выражений — проверяйте план.

Партиционирование против шардирования

Партиционирование — внутри одной БД/сервера. Шардирование — между серверами (Citus, вручную).

Когда не помогает

  • нет естественного ключа, по которому фильтруют;
  • запросы затрагивают все партиции;
  • небольшие таблицы: только усложнение.

Вопросы с ответами