Перейти к содержанию
Innovialabs

Шардирование и партиционирование: как масштабировать базу

Продвинутое4 мин

Коротко

Партиционирование делит большую таблицу на части внутри одного сервера, а шардирование распределяет данные по нескольким серверам по ключу шарда; начинайте с партиционирования и шардируйте, только когда один сервер действительно не справляется.

Коротко о разнице

Партиционирование делит одну логическую таблицу на несколько физических на том же сервере. Приложение работает с одной базой, а PostgreSQL сам кладёт строки в нужную партицию.

Шардирование распределяет данные по нескольким независимым серверам. Каждый шард хранит часть строк, выбранную по ключу шарда. Приложение или прокси-слой должны знать, где лежит каждая строка.

Партиционирование решает задачу «таблица слишком большая, её тяжело обслуживать». Шардирование решает задачу «одна машина не выдерживает объём записи или данных». Вторая проблема встречается гораздо реже и обходится гораздо дороже.

Партиционирование в PostgreSQL

В PostgreSQL есть декларативное партиционирование с тремя стратегиями.

СтратегияКак делятся строкиТипичное применение
RangeПо диапазонам значений, например датамЛоги, события, заказы по месяцам
ListПо перечню значенийРегион, страна, тип клиента
HashПо хешу колонки по модулю NРавномерное распределение, когда нет естественного диапазона

Самый частый случай — range по времени:

CREATE TABLE events (
  id         bigint GENERATED ALWAYS AS IDENTITY,
  created_at timestamptz NOT NULL,
  payload    jsonb,
  PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);

CREATE TABLE events_2026_10 PARTITION OF events
  FOR VALUES FROM ('2026-10-01') TO ('2026-11-01');

List и hash выглядят похоже:

CREATE TABLE customers (...) PARTITION BY LIST (region);
CREATE TABLE customers_uz PARTITION OF customers FOR VALUES IN ('uz');

CREATE TABLE sessions (...) PARTITION BY HASH (user_id);
CREATE TABLE sessions_p0 PARTITION OF sessions
  FOR VALUES WITH (MODULUS 4, REMAINDER 0);

Что это даёт на практике:

  • Partition pruning: запрос с фильтром по ключу партиционирования читает только нужные партиции.
  • Дешёвое удаление: DETACH PARTITION и DROP TABLE вместо огромного DELETE, который раздувает таблицу.
  • Индексы меньше, а VACUUM и переиндексация идут быстрее.

Важные ограничения: первичный ключ и уникальные ограничения должны включать ключ партиционирования, а запросы без фильтра по нему всё равно затрагивают все партиции.

Горизонтальное шардирование

При шардировании каждый сервер хранит часть данных. Главное решение — ключ шарда:

  • Хороший ключ: есть почти в каждом запросе, равномерно распределяет нагрузку, почти не меняется. Например, tenant_id в B2B SaaS или user_id в пользовательском приложении.
  • Плохой ключ: мало уникальных значений (страна), перекос (один огромный клиент) или время для записи (все новые строки летят в последний шард).

Способы сопоставить ключ и шард:

  • По хешу: равномерно, но при добавлении шардов данные приходится переносить, если не использовать много виртуальных бакетов.
  • По диапазону: просто, но легко получить горячие точки.
  • Справочник (lookup-таблица): гибко, но нужен дополнительный сервис поиска.

Инструменты вроде Citus для PostgreSQL или Vitess для MySQL берут на себя маршрутизацию, но ограничения дизайна никуда не исчезают.

Межшардовые запросы: настоящая цена

Как только данные разнесены, всё, что затрагивает несколько шардов, усложняется:

  • JOIN между шардами требует совместного размещения (связанные таблицы шардируются по одному ключу) или склейки в приложении.
  • Агрегации (COUNT, SUM, отчёты) нужно отправлять на все шарды и объединять результаты.
  • Транзакции между шардами требуют двухфазного коммита или паттерна saga — и новых сценариев отказа.
  • Уникальность и последовательности перестают быть глобальными по умолчанию.

Поэтому после шардирования аналитику обычно выносят в отдельное хранилище данных.

Когда это преждевременно

Партиционирование рано, если:

  • Таблица спокойно помещается в память, а запросы быстрые при правильных индексах.
  • Большинство запросов не фильтрует по естественному ключу партиционирования.

Шардирование рано, если вы ещё не попробовали:

  • Оптимизацию запросов и индексов, пул соединений.
  • Вертикальное масштабирование и реплики для чтения.
  • Партиционирование и архивирование старых данных.
  • Вынос аналитики с основной базы.

Разумный порядок: оптимизировать, увеличить сервер, добавить реплики, партиционировать, потом шардировать.

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

  • Выбирать ключ шарда только под сегодняшние запросы, не думая о будущих отчётах.
  • Создавать тысячи мелких партиций — планировщик начинает работать медленнее.
  • Забывать заранее создавать будущие партиции, и вставки падают в начале нового месяца.
  • Шардировать, чтобы «починить» медленные запросы, хотя причина была в отсутствующих индексах.

Частые вопросы

Да. Частая схема: шардировать по клиенту или пользователю, а большие таблицы внутри шарда партиционировать по времени. Начинайте с партиционирования и добавляйте шардинг только при реальной необходимости.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.