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

Урок объясняет партиционирование — приём, который ускоряет запросы и упрощает перезагрузку данных.

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

Зачем резать данные на части

Таблица событий за три года — это миллиарды строк. Но почти любой запрос смотрит на узкий период: «события за вчера», «продажи за июнь». Если данные физически разложены по папкам-партициям date=2026-06-21/, движок прочитает только нужную партицию и пропустит остальные. Это называется partition pruning (отсечение партиций).

/events/
   date=2026-06-20/part.parquet
   date=2026-06-21/part.parquet   ← запрос за 21-е читает только это
   date=2026-06-22/part.parquet

Бонус для конвейеров

Партиции — лучший друг идемпотентности. Если конвейер за 21 июня нужно перезапустить (пришли исправленные данные), он просто перезаписывает партицию date=2026-06-21 целиком, не трогая остальные дни. Никаких дублей, никакой ручной чистки.

Эта связка партиций и идемпотентности — один из самых важных приёмов в дата-инженерии, и мы ещё вернёмся к ней в разделе про повторные запуски. Запомните пока главное: если данные физически разложены по дням, то «загрузка за день» и «перезагрузка за день» — это одна и та же безопасная операция перезаписи папки. Без партиций пришлось бы аккуратно удалять старые строки за дату перед вставкой новых, что куда сложнее и опаснее.

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

В реляционной базе аналог — индекс или столбец-партиция, по которому фильтруют. Смоделируем «отсечение» через WHERE по дате и сравним с агрегацией по партициям.

CREATE TABLE events (id INTEGER PRIMARY KEY, day TEXT, kind TEXT);
INSERT INTO events VALUES
    (1,'2026-06-20','click'), (2,'2026-06-20','view'),
    (3,'2026-06-21','click'), (4,'2026-06-21','click'),
    (5,'2026-06-22','view');

-- запрос за один день: движок отсекает остальные партиции
SELECT day, COUNT(*) AS cnt
FROM events
WHERE day = '2026-06-21'
GROUP BY day;

Покажем логику выбора партиции на чистом Python — как конвейер раскладывает записи по «папкам».

from collections import defaultdict

rows = [("2026-06-20","a"), ("2026-06-21","b"), ("2026-06-21","c")]
partitions = defaultdict(list)
for day, val in rows:
    partitions[f"date={day}"].append(val)
for part, items in sorted(partitions.items()):
    print(part, "->", items)

Вывод:

date=2026-06-20 -> ['a']
date=2026-06-21 -> ['b', 'c']

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

  • Партиционировать по столбцу с тысячами значений. Партиция по user_id создаст миллионы крошечных файлов — это убивает производительность. Партиционируют по дате или региону.
  • Слишком мелкие партиции. Партиции по часам при малом объёме данных дают много мелких файлов (small files problem).
  • Забыть фильтр по ключу партиции. Если в запросе нет WHERE date = ..., отсечение не сработает и читается всё.

Итог

  • Партиционирование делит данные по ключу (обычно дате) на отдельные части.
  • Partition pruning читает только нужные партиции, ускоряя запросы.
  • Перезапись одной партиции — простой способ сделать загрузку идемпотентной.
Проверьте себя
1. Что такое partition pruning?
AУдаление старых данных по расписанию
BОтсечение ненужных партиций при запросе, чтобы читать только релевантные
CСжатие файлов внутри партиции
DОбъединение всех партиций в одну
2. Почему партиционирование по user_id обычно плохая идея?
Auser_id нельзя использовать в SQL
BПолучаются миллионы крошечных партиций-файлов, что убивает производительность
CЭто запрещено стандартом SQL
DЭто всегда лучшая стратегия
3. Как партиционирование помогает идемпотентности конвейера?
AОно шифрует данные
BМожно перезаписать одну партицию (например, за день) целиком, не трогая остальные
CОно запрещает повторные запуски
DНикак не помогает