Learning Platform
Глоссарий Troubleshooting
Урок 03.06 · 15 мин
Средний
PARTITION BYLifecycleTTLOver-partitioning

PARTITION BY: жизненный цикл, не оптимизация запросов

Одно из самых частых заблуждений при проектировании ClickHouse таблиц — использование PARTITION BY для ускорения запросов. Официальная документация ClickHouse прямо предупреждает:

“Partitioning does not speed up queries (in contrast to the ORDER BY expression)”

PARTITION BY определяет, как данные группируются в отдельные директории на диске. Каждая партиция содержит свои parts, которые никогда не объединяются с parts из других партиций. Это свойство делает партиции инструментом управления жизненным циклом данных, а не оптимизации запросов.


Зачем нужен PARTITION BY

PARTITION BY решает три задачи:

1. TTL и автоматическое удаление. ClickHouse удаляет данные по TTL целыми партициями. Если партиция = месяц, при истечении TTL ClickHouse дропает целую директорию, а не ищет и удаляет отдельные строки. Это мгновенная операция.

2. DETACH / ATTACH для архивирования. Партицию можно отключить от таблицы (DETACH) без удаления файлов. Позже её можно подключить обратно (ATTACH) или перенести на другой сервер. Это позволяет перемещать исторические данные на дешёвое хранилище.

3. REPLACE для bulk-обновлений. ALTER TABLE REPLACE PARTITION атомарно заменяет партицию новыми данными. Это паттерн для перезагрузки данных из внешних источников: подготовить данные во временной таблице, затем заменить партицию.


Правила размеров

МетрикаРекомендация
Размер одной партиции1-300 ГБ
Общее число партицийДесятки или сотни (не тысячи)
МаксимумМенее 1000 партиций

Типичные паттерны

-- Ежемесячное партиционирование (стандарт)
-- ~12 партиций в год, каждая от нескольких ГБ до сотен ГБ
PARTITION BY toYYYYMM(event_date)

-- Ежегодное партиционирование (длительное хранение)
-- Для данных, хранимых годами с редким удалением
PARTITION BY toYear(event_date)

-- Ежедневное партиционирование (высокий объём + короткий retention)
-- 100+ ГБ в день, retention 30-90 дней
PARTITION BY toDate(event_date)

Для небольших таблиц (менее 100 миллионов строк) опустите PARTITION BY полностью — все данные будут в одной партиции. Это нормально и даже предпочтительно: меньше overhead на управление.

Партиционирование: месячное vs по user_id
PARTITION BY toYYYYMM(event_date)12 партиций в годМесячное партиционирование: предсказуемое число партиций. TTL удаляет целые месяцы мгновенно. DETACH PARTITION '202401' архивирует январь. Размер партиции пропорционален месячному объёму данных. При 10 ГБ/день = ~300 ГБ/месяц -- в пределах нормы.
PARTITION BY user_id1 000 000+ партицийПартиционирование по user_id при миллионе пользователей = миллион партиций. Каждый INSERT создаёт parts в тысячах партиций. ClickHouse не успевает мержить parts -- число parts превышает parts_to_throw_insert (по умолчанию 300 на партицию). INSERT начинает возвращать ошибку 'Too many parts'.

Anti-pattern: over-partitioning

Over-partitioning — это создание слишком большого числа партиций. Каждый INSERT создаёт parts в каждой затронутой партиции. Фоновый merge объединяет parts только внутри одной партиции. Если партиций тысячи, merge не успевает за INSERT, и число parts растёт бесконтрольно.

Пример: PARTITION BY user_id при миллионе пользователей:

  • Каждый INSERT может затрагивать тысячи user_id = тысячи маленьких parts
  • Merge не успевает: parts накапливаются
  • При достижении parts_to_throw_insert (по умолчанию 300 parts на партицию) ClickHouse отклоняет INSERT
-- Anti-pattern: не делайте так
CREATE TABLE user_events (
    user_id UInt64,
    event_date Date,
    data String
) ENGINE = MergeTree()
PARTITION BY user_id         -- МИЛЛИОНЫ партиций!
ORDER BY (event_date)
WARNING

Более 1000 партиций — сигнал проблемы. Проверяйте текущее состояние:

SELECT partition, count() AS parts
FROM system.parts
WHERE table = 'events' AND active = 1
GROUP BY partition
ORDER BY parts DESC
LIMIT 10

Partition pruning — бонус, не цель

ClickHouse выполняет partition pruning: если запрос содержит условие на столбец PARTITION BY, ClickHouse пропускает партиции, не соответствующие условию. Это ускоряет запросы, но:

  • Partition pruning — грубый (целые месяцы/дни), а не гранулярный как ORDER BY pruning
  • ORDER BY pruning работает внутри каждой партиции и всегда эффективнее
  • Проектировать PARTITION BY ради partition pruning — ошибка: выбирайте PARTITION BY по lifecycle needs, а ORDER BY — по query needs

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

  1. PARTITION BY — инструмент жизненного цикла: TTL удаление, DETACH/ATTACH архивирование, REPLACE для bulk-обновлений. Не инструмент оптимизации запросов.
  2. Размер партиции: 1-300 ГБ, общее число: десятки или сотни. Менее 1000 партиций.
  3. toYYYYMM(event_date) — стандартный выбор для большинства таблиц с временными данными.
  4. Маленькие таблицы — опустите PARTITION BY полностью. Одна партиция — это нормально.
  5. Over-partitioning (PARTITION BY user_id при миллионах пользователей) приводит к ошибке “Too many parts” и отказу INSERT.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 3. Таблица принимает 100 ГБ данных в день. Retention -- 2 года. Какой PARTITION BY обеспечит управляемое число партиций и эффективное TTL-удаление?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 8