Короткий ответ
Партиционирование по диапазону дат обычно лучший выбор для таблиц событий/логов, так как совпадает с паттерном доступа (чаще читают/пишут свежие данные) и позволяет дешёво удалять старые данные целыми партициями (DROP PARTITION) вместо построчного DELETE; партиционирование по хешу даёт равномерное распределение без «горячего» диапазона, но не даёт дешёвого способа избавляться от старых данных и не ускоряет диапазонные запросы по времени.
Как это работает подробнее
PostgreSQL Declarative Partitioning создаёт родительскую таблицу и набор физических партиций-наследников; планировщик использует partition pruning, чтобы при запросе с условием на партиционирующий ключ сканировать только нужные партиции, что также уменьшает объём данных для VACUUM/ANALYZE.
Сравнение
- Компромисс. Range-партиционирование по дате даёт удобное устаревание данных, но требует дисциплины по созданию новых партиций вовремя и миграции существующей большой таблицы на партиционированную структуру (обычно через создание новой таблицы и постепенный перенос данных); критерий выбора — доминирующий паттерн доступа (по времени vs равномерно по ключу) и необходимость быстрого устаревания старых данных.
Пример кода
example.sql
CREATE TABLE events (
id BIGSERIAL,
user_id BIGINT NOT NULL,
payload JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);
CREATE TABLE events_2026_01 PARTITION OF events
FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
CREATE TABLE events_2026_02 PARTITION OF events
FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');
-- Запрос за январь сканирует только одну партицию (partition pruning)
EXPLAIN SELECT * FROM events WHERE created_at >= '2026-01-10' AND created_at < '2026-01-20';
-- Удаление старых данных почти мгновенно вместо DELETE с полным сканом:
DROP TABLE events_2026_01;Что использовать на практике
- Практика. Для таблицы событий типична схема «партиция на день/неделю/месяц» по created_at, автоматическое создание новых партиций заранее (pg_partman) и DROP/detach старых партиций вместо DELETE; партиционирующий ключ должен входить в большинство «горячих» запросов и в PRIMARY KEY/UNIQUE-ограничения.
Подводные камни
- Ошибка. Выбирают ключ партиционирования, не используемый в фильтрах реальных запросов, из-за чего partition pruning не работает; создают слишком много мелких партиций, увеличивая накладные расходы планировщика.