Что такое партиционирование и зачем оно нужно
Партиционирование делит одну логическую таблицу на несколько физических частей — партиций, которые лежат в отдельных файлах, но для запросов выглядят как одна таблица. Идея та же, что и у отдельных таблиц по месяцам, только сервер сам решает, в какую партицию писать и из какой читать, без правок в коде приложения.
Главный эффект — 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.
Итог: стоит ли внедрять партиционирование
Перед тем как разбивать таблицу на секции, ответьте на несколько вопросов:
- Растёт ли таблица настолько, что старые данные хочется удалять целыми блоками.
- Есть ли у запросов условие на будущий столбец партиционирования.
- Готовы ли вы включить этот столбец в первичный ключ.
- Нужны ли внешние ключи на эту таблицу — если да, партиционирование не подойдёт.
- Настроено ли автоматическое добавление новых партиций по расписанию.