К основному содержимому

Партиционирование таблиц MySQL: когда оно помогает

MySQL / MariaDB · 29.09.2026

Что такое партиционирование и зачем оно нужно

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

Главный эффект — partition pruning: если запрос содержит условие на столбец партиционирования, MySQL сканирует только нужные партиции, а не всю таблицу. Для таблицы логов на сотни миллионов строк это превращает скан всей таблицы в скан одного месяца.

Виды партиционирования: RANGE, LIST, HASH

В MySQL и MariaDB доступно несколько типов:

ТипПринцип деленияТипичный сценарий
RANGEПо диапазону значений столбцаЛоги и заказы по дате
LISTПо фиксированному списку значенийДанные по регионам или статусам
HASHПо хеш-функции от столбцаРавномерное распределение без явного ключа
KEYКак HASH, но на встроенной функции MySQLБыстрое разделение без своей формулы

RANGE по дате — самый частый случай на практике: старые партиции легко удалить целиком одной командой вместо медленного DELETE по миллионам строк.

Пример: партиционирование таблицы логов по месяцам

Партиционирование задаётся при создании таблицы через PARTITION BY:

CREATE TABLE access_log (
  id BIGINT AUTO_INCREMENT,
  created_at DATE NOT NULL,
  ip VARCHAR(45),
  PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (TO_DAYS(created_at)) (
  PARTITION p2026_01 VALUES LESS THAN (TO_DAYS('2026-02-01')),
  PARTITION p2026_02 VALUES LESS THAN (TO_DAYS('2026-03-01')),
  PARTITION pmax VALUES LESS THAN MAXVALUE
);

Обратите внимание: столбец партиционирования обязан входить в первичный ключ. Это ограничение MySQL, и его нельзя обойти — приходится проектировать ключ заранее, до появления реальных данных.

Как удалить старые данные без DELETE

Вместо медленного DELETE FROM access_log WHERE created_at < '2026-01-01', которое пишет в бинлог по строке, партицию можно отбросить целиком:

ALTER TABLE access_log DROP PARTITION p2026_01;

Операция почти мгновенная, потому что физически удаляется файл партиции, а не строки из него. Для таблиц с логами и метриками это основная причина внедрять партиционирование. Подробнее о том, как читать план запроса и убедиться, что pruning действительно работает, — в статье про EXPLAIN и чтение плана.

Когда партиционирование не помогает

Есть сценарии, где секции только добавляют сложность без выигрыша в скорости:

  • Таблица небольшая — до нескольких миллионов строк, индекса обычно достаточно.
  • Запросы не фильтруют по столбцу партиционирования, и pruning не срабатывает.
  • Много запросов с JOIN по внешнему ключу, не совпадающему со столбцом партиций.
  • Внешние ключи на партиционированную таблицу — MySQL их не поддерживает вовсе.

Обслуживание партиций: добавление и реорганизация

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

ALTER TABLE access_log REORGANIZE PARTITION pmax INTO (
  PARTITION p2026_03 VALUES LESS THAN (TO_DAYS('2026-04-01')),
  PARTITION pmax VALUES LESS THAN MAXVALUE
);

После реорганизации проверьте распределение строк по секциям через information_schema.partitions, чтобы убедиться, что данные не скопились в одной партиции. Если партиции стали крупнее, чем рассчитывал буферный пул, пересмотрите его размер в статье про настройку my.cnf.

Итог: стоит ли внедрять партиционирование

Перед тем как разбивать таблицу на секции, ответьте на несколько вопросов:

  • Растёт ли таблица настолько, что старые данные хочется удалять целыми блоками.
  • Есть ли у запросов условие на будущий столбец партиционирования.
  • Готовы ли вы включить этот столбец в первичный ключ.
  • Нужны ли внешние ключи на эту таблицу — если да, партиционирование не подойдёт.
  • Настроено ли автоматическое добавление новых партиций по расписанию.
← Назад в базу знаний Задать вопрос поддержке