Секціонування ділить одну логічну таблицю на кілька фізичних частин за значенням колонки. Для запитів таблиця одна, а на диску - окремі файли на кожну секцію.
CREATE TABLE activity_log (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
created_at DATETIME NOT NULL,
payload JSON,
PRIMARY KEY (id, created_at)
)
PARTITION BY RANGE COLUMNS (created_at) (
PARTITION p2026_08 VALUES LESS THAN ('2026-09-01'),
PARTITION p2026_09 VALUES LESS THAN ('2026-10-01'),
PARTITION p2026_10 VALUES LESS THAN ('2026-11-01'),
PARTITION pmax VALUES LESS THAN (MAXVALUE)
);
Типи: RANGE (діапазони, найчастіше дати), LIST (списки значень), HASH і KEY (рівномірний розподіл).
Де секціонування справді допомагає:
- видалення старих даних. Замість
DELETEмільйонів рядків (довга транзакція, роздутий undo, затримка реплік, місце на диску не звільняється):
ALTER TABLE activity_log DROP PARTITION p2026_08; -- миттєво, з файлом
- відсікання секцій (partition pruning): запит з умовою на ключ секціонування читає лише потрібні секції. В
EXPLAIN- колонкаpartitions; - обслуговування частинами: перебудова чи аналіз окремої секції.
Обмеження, про які часто дізнаються запізно:
- кожен унікальний ключ, включно з первинним, мусить містити колонку секціонування. Тому в прикладі первинний ключ
(id, created_at). Унікальністьemailу секціонованій за датою таблиці забезпечити неможливо; - зовнішні ключі не підтримуються для секціонованих таблиць InnoDB - ні з неї, ні на неї;
- запити без умови на ключ секціонування перебирають усі секції - це повільніше, ніж одна несекціонована таблиця з хорошим індексом;
- глобальних індексів немає: індекс існує окремо в кожній секції;
- до 8192 секцій, але сотні секцій уже уповільнюють відкриття таблиці й планування.
Коли секціонування шкодить: як «прискорювач» звичайної OLTP-таблиці. Таблиця orders на 50 мільйонів рядків з правильними індексами працює чудово - B-дерево на 50 млн рядків має лише 3-4 рівні. Секціонування за user_id не дасть нічого, крім обмежень.
Найкращий кандидат: журнали, події, метрики, історія - дані, що додаються за часом і видаляються за часом, а запити майже завжди мають умову на дату.
Супровід: секції на майбутнє треба створювати заздалегідь (крон-задача раз на місяць: REORGANIZE PARTITION pmax INTO (...)). Laravel-міграції секціонування не підтримують - лише DB::statement().