Партиционирование данных

Партиции делят таблицу на крупные независимые блоки — обычно по месяцам.

Партиционирование (PARTITION BY) — деление данных таблицы на крупные логические части (например, по месяцам), каждая из которых хранится и обслуживается отдельно.

Партиция — это не то же, что ORDER BY

Легко спутать два понятия. ORDER BY сортирует строки внутри куска и даёт индекс для отсечения гранул. PARTITION BY работает «крупнее»: он раскладывает данные по отдельным партициям, и куски никогда не сливаются между разными партициями. Типичный выбор — партиция по месяцу:

CREATE TABLE events
(
    event_date Date,
    user_id    UInt32,
    value      Float64
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(event_date)
ORDER BY (event_date, user_id);

Здесь toYYYYMM(event_date) превращает дату в число вида 202401 — все события января 2024 попадут в одну партицию.

Что дают партиции

1. Отсечение целых партиций

Запрос WHERE event_date >= '2024-03-01' позволяет движку сразу отбросить все партиции до марта — он даже не заглядывает в их куски. Это грубое, но очень дешёвое отсечение поверх тонкого отсечения по гранулам.

2. Мгновенное удаление старых данных

Удалить «всё за январь» можно не построчным DELETE, а сбросом целой партиции — это почти мгновенная операция над файлами:

ALTER TABLE events DROP PARTITION 202401;

Так удобно соблюдать политику хранения «храним данные год».

Сколько партиций делать

Золотое правило: немного крупных партиций. По месяцам — почти всегда хорошо. По дням на большом сроке — уже много партиций. А вот партиционировать по высококардинальной колонке (например, по user_id) нельзя: получатся десятки тысяч партиций, и сервер захлебнётся в метаданных.

PARTITION BYОценка
toYYYYMM(date)отлично — десятки партиций
toDate(date) (по дням)осторожно — сотни/тысячи
user_idплохо — взрыв числа партиций

Как работает под капотом

Каждая партиция — это набор кусков с общим значением ключа партиционирования. Слияние идёт только внутри партиции. В метаданных партиции хранятся отдельно, поэтому DROP PARTITION — это удаление файлов, а не сканирование строк.

Частые ошибки

  • Слишком мелкие партиции. По дням или по высококардинальному полю — взрыв числа партиций, деградация и предупреждения сервера.
  • Путать партицию с индексом. Партиция — грубое деление; тонкую фильтрацию делает ORDER BY/индекс.
  • Удалять старое построчным DELETE. Дешевле и быстрее DROP PARTITION или TTL.

Итоги

  • PARTITION BY крупно делит таблицу (обычно по месяцам).
  • Партиции отсекаются целиком и удаляются одной операцией.
  • Делайте немного крупных партиций; не партиционируйте по высококардинальному полю.
  • Партиция дополняет ORDER BY, а не заменяет его.
Проверьте себя
1. Какое распространённое и безопасное правило партиционирования?
AПартиционировать по user_id
BПартиционировать по месяцу через toYYYYMM(date)
CДелать партицию на каждую строку
DВообще не использовать ORDER BY
2. Как быстрее всего удалить все данные за январь 2024?
ADELETE FROM events WHERE month = 1 построчно
BALTER TABLE events DROP PARTITION 202401
CПересоздать таблицу
DОтключить сервер
3. Чем партиционирование отличается от ORDER BY?
AЭто одно и то же
BPARTITION BY — крупное деление на независимые блоки, ORDER BY — сортировка и индекс внутри куска
CPARTITION BY сортирует строки, ORDER BY делит таблицу
DORDER BY удаляет данные