awesome-everything EN
↑ Обратно к восхождению

Базы данных

Партиционирование против шардирования: одно слово, два разных понятия

Суть Партиционирование — это pruning запросов и управление retention на одном инстансе; шардирование — масштабирование пропускной способности на множестве инстансов. Они дополняют друг друга и обычно используются совместно в продакшне.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 10 min

Команда добавляет PARTITION BY RANGE (created_at) к своей таблице events и называет это «шардированием базы данных». Месяц спустя они удивляются, почему пропускная способность записи не улучшилась. Партиционирование и шардирование часто путают — они решают разные проблемы на разных масштабах.

Партиционирование: один Postgres, таблица разбита для pruning

Декларативное партиционирование таблиц (введено в PostgreSQL 10) разбивает одну таблицу на именованные подтаблицы — партиции, все живущие на одном экземпляре Postgres.

-- Один Postgres, одна машина, множество партиций
CREATE TABLE events (
  id BIGINT,
  tenant_id INT,
  created_at TIMESTAMPTZ,
  payload JSONB
) 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');

Postgres получает две вещи от этого:

  1. Partition pruning: запрос с WHERE created_at >= '2026-02-01' сканирует только нужные партиции, а не всю таблицу.
  2. Мгновенное удаление для retention: удаление месяца данных — DROP TABLE events_2026_01 — мгновенно, без долгого DELETE, без bloat мёртвых строк, без массового VACUUM.

Критическое ограничение: партиционирование не увеличивает пропускную способность за пределы одной машины. Все записи всё равно идут на тот же primary Postgres; все чтения делят тот же CPU и RAM.

Шардирование: множество экземпляров Postgres, маршрутизация по ключу

Шардирование распределяет строки по N физически отдельным экземплярам Postgres. Каждый экземпляр держит подмножество данных. Записи и чтения для данного ключа шарда идут на Postgres того шарда — параллельный, независимый IO и CPU.

ИзмерениеПартиционированиеШардирование
Экземпляры PostgresОдинМного (N)
Увеличивает пропускную способность записи?НетДа (~N×)
Основное преимуществоPartition pruning, быстрый DROP для retentionВыход за потолок одной машины
Кросс-таблица joinsБесплатно (всё на одном инстансе)Дорого при кросс-шард; бесплатно при ко-локации
Операционный множительНизкий (всё ещё один инстанс)N× операций на каждый шард
Доступно сPostgreSQL 10 (декларативное)Через расширение Citus или маршрутизацию на уровне приложения

Как они сочетаются в продакшне

Реальные продакшн-системы обычно используют оба — партиционирование внутри каждого шарда:

Шард 0: экземпляр Postgres, хранящий tenant_id 1–500
  └── таблица events: PARTITION BY RANGE (created_at)
        ├── events_2026_01 (январские строки для клиентов 1-500)
        ├── events_2026_02 (февральские строки для клиентов 1-500)
        └── ...

Шард 1: экземпляр Postgres, хранящий tenant_id 501–1000
  └── таблица events: те же месячные партиции
        ├── events_2026_01
        └── ...

Ключ шарда (tenant_id) маршрутизирует трафик на нужный экземпляр Postgres. Внутри этого инстанса временная партиция означает: запрос WHERE tenant_id = 42 AND created_at >= '2026-02-01' обрезается до февральской партиции. Retention — DROP PARTITION events_2026_01 на каждый шард.

Опытная интуиция: партиционировать для того, что вы бы сделали на единственной машине в любом случае (retention time-series, pruning запросов для больших таблиц); шардировать только когда пределы пропускной способности и хранилища одного Postgres измерены и доказаны как реальное ограничение.

Почему это работает

Почему Postgres поддерживает до ~1–2k партиций в OLTP-нагрузках, но ~10k в OLAP? Метаданные партиций загружаются в рабочую память планировщика при каждом запросе — большое число партиций замедляет генерацию плана. Для OLTP-запросов, касающихся одной-двух партиций, накладные расходы плана от 10k партиций доминируют над временем выполнения. OLAP-запросы, параллельно сканирующие много партиций, могут амортизировать стоимость планирования. Практический предел в OLTP — около 1–2k партиций на таблицу.

Викторина

Команда добавляет PARTITION BY RANGE (created_at) к своей крупнейшей таблице. Какую проблему это решает?

Викторина

В продакшн-кластере Citus каково типичное сочетание партиционирования и шардирования?

Вспомните перед уходом
  1. 01
    Каковы два главных преимущества декларативного партиционирования таблиц в Postgres и каково его ключевое ограничение?
  2. 02
    B2B SaaS шардирует orders по tenant_id по 16 экземплярам Postgres. Каждый инстанс также партиционирует orders по месяцу created_at. Что делает запрос WHERE tenant_id = 42 AND created_at >= '2026-02-01'?
  3. 03
    Почему «партиционировать для управляемости, шардировать для мощности» — это опытная эвристика?
Итог

Партиционирование (декларативное PARTITION BY в PostgreSQL 10+) разбивает одну таблицу на подтаблицы на одном экземпляре Postgres — оно улучшает pruning запросов и делает DROP для retention мгновенным, но не увеличивает пропускную способность за пределы одной машины. Шардирование распределяет строки по N отдельным экземплярам Postgres с помощью ключа шарда, давая примерно N× пропускной способности и мощности хранилища ценой N× операционной сложности. Продакшн-системы используют оба: шардируют по tenant_id для кросс-машинной мощности и партиционируют по времени внутри каждого шарда для pruning и retention. Опытное правило: партиционировать свободно, когда таблица достаточно велика, чтобы выиграть; шардировать только после измерения и доказательства, что пределы одного Postgres — реальное бутылочное горлышко.

Связанные уроки
встречается в140
Продолжить восхождение ↑Ко-локация и Citus: инвариант, делающий шардирование пригодным к использованию
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.