Базы данных

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

Cloudflare обрабатывает 1 триллион DNS запросов в месяц. Хранить такой объём в одной таблице невозможно. Решение: партиционирование по дням с автоматическим удалением через DROP PARTITION. Удаление дневного лога (миллиарды строк) занимает 50ms вместо часов.

  • **Datadog**: TimescaleDB для 100+ миллиардов временных меток метрик в день с автоматическим compression
  • **Cloudflare**: PostgreSQL range partitioning для DNS logs - DROP PARTITION вместо медленного DELETE
  • **Zalando**: pg_partman для управления сотнями партиций в продакшне

Типы партиционирования

Партиционирование - разбиение большой таблицы на меньшие части (партиции) на одном сервере. В отличие от шардинга - нет network overhead, транзакции между партициями работают, JOIN возможен. Три основных типа: range (по диапазону), hash (по хешу), list (по списку значений).

PostgreSQL 10+ поддерживает declarative partitioning. TimescaleDB строится поверх неё для time-series: автоматически создаёт партиции (chunks) по времени и выполняет partition pruning. Это позволяет хранить 2+ лет данных и быстро удалять старые.

Какой тип партиционирования лучше для таблицы логов с частыми запросами "за последний месяц" и регулярным удалением данных старше года?

Range Partitioning в деталях

Range partitioning - наиболее популярный тип для time-series и архивных данных. Главное преимущество: partition detachment (DROP PARTITION) работает за O(1) - просто удаляет ссылку на файл данных. DELETE 100 миллионов строк может занять часы. DROP PARTITION - секунды.

Partition key constraints: в PostgreSQL все запросы по partition key автоматически направляются в нужную партицию. Но если partition key не в WHERE - полный scan всех партиций. Constraint exclusion: PostgreSQL автоматически исключает неподходящие партиции при наличии CHECK constraints.

Почему DROP PARTITION быстрее чем DELETE всех строк партиции?

Partition Pruning

Partition pruning - оптимизация планировщика запросов: при наличии условия на partition key в WHERE, PostgreSQL исключает нерелевантные партиции из плана. Запрос к таблице с 1000 партиций может читать только 1-2.

Runtime pruning (PostgreSQL 12+): partition pruning применяется не только при планировании но и при выполнении. Полезно для prepared statements и функций - partition key может быть параметром, определяемым в runtime.

Таблица секционирована по month(created_at). Запрос: WHERE EXTRACT(YEAR FROM created_at) = 2024. Сколько партиций будет просканировано?

PostgreSQL Partitioning в продакшне

PostgreSQL declarative partitioning (10+) поддерживает: глобальные индексы (уникальные constraint на всей таблице), foreign key на секционированные таблицы, DEFAULT партицию для данных без явной партиции. pg_partman - extension для автоматического управления партициями.

При добавлении строки с датой, для которой нет партиции, что происходит?

Когда партиционировать

Партиционирование добавляет сложность и overhead планировщика. Оно оправдано когда: таблица очень большая (100M+ строк), нужно регулярно удалять старые данные, большинство запросов содержат фильтр по partition key.

  • 100M+ строк и медленные запросы по времени - кандидат для range partitioning
  • Регулярное удаление старых данных (logs, events) - DROP PARTITION вместо DELETE
  • Большинство запросов фильтруют по partition key - pruning сработает
  • Архивирование: перенести старые партиции на cheaper storage (tablespaces)

Не стоит партиционировать: маленькие таблицы (<10M строк), когда запросы не фильтруют по partition key, когда нужно часто делать JOIN между партициями и другими таблицами (planner overhead растёт).

Партиционирование всегда ускоряет запросы

Партиционирование ускоряет запросы ТОЛЬКО если они содержат фильтр по partition key. Запросы без такого фильтра сканируют ВСЕ партиции - медленнее чем без партиционирования из-за overhead.

Плановщик PostgreSQL при большом количестве партиций (1000+) тратит больше времени на planning. Без pruning каждый запрос - overhead на анализ всех партиций.

Таблица transactions: 50M строк, INSERT 100,000/день, запросы типа "транзакции пользователя за всё время". Нужно ли партиционирование?

Ключевые идеи

  • **Range partitioning по дате**: DELETE старых данных = DROP PARTITION (O(1) vs O(N))
  • **Partition pruning**: работает только при прямом фильтре на partition key без функций
  • **Когда НЕ нужно**: маленькие таблицы, запросы без фильтра по partition key, сложные JOIN

Связанные темы

Партиционирование - локальный аналог шардинга с другими trade-offs:

  • Шардинг — Партиционирование = шардинг на одном сервере; шардинг = разные серверы
  • Time-series БД — TimescaleDB добавляет автоматическое партиционирование и compression для PostgreSQL
  • Индексы — Локальные и глобальные индексы на секционированных таблицах - важный trade-off

Вопросы для размышления

  • Таблица messages: 10 млрд строк, 99% запросов по user_id, периодически чистить старые >1 года. Как партиционировать?
  • Почему индексы на секционированных таблицах сложнее чем обычные? Что такое local vs global index?
  • В каком сценарии партиционирование замедлит запросы вместо их ускорения?

Связанные уроки

  • dist-14-sharding
Партиционирование таблиц

0

1

Войти