Как разделить большую таблицу по студентам для оптимизации запросов
Что проверяют
Понимаете ли вы, что делить таблицу надо под конкретные запросы, и знаете ли разницу между индексом, партиционированием и шардингом. Следом обычно спрашивают, как перенести работающую таблицу на новую схему без простоя и что поменяется в коде на Go.
Как отвечать
Начните с диагностики: какие запросы медленные, что показывает EXPLAIN ANALYZE, хватает ли составного индекса вроде (student_id, created_at). Часто этого достаточно, и делить ничего не нужно.
Если таблица действительно огромная, в PostgreSQL есть декларативное партиционирование:
- по хешу:
PARTITION BY HASH (student_id)и секцииFOR VALUES WITH (MODULUS 16, REMAINDER 0). Нагрузка ложится равномерно, запрос по одному студенту идёт в одну секцию; - по диапазону: по учебному году или дате. Удобно для архива: старую секцию можно отсоединить через
DETACH PARTITIONвместо долгогоDELETE; - по списку: по факультету или региону, если запросы почти всегда идут с таким фильтром.
Ключ партиционирования должен стоять в WHERE, иначе планировщик не отбросит лишние секции и прочитает все. Первичный ключ и уникальные ограничения обязаны его включать.
Шардинг по разным серверам это следующий шаг, когда не хватает одной машины. В Go его обычно делают на уровне приложения: номер шарда считается от student_id, на каждый шард свой pgxpool.Pool. Цена: запросы по многим студентам и транзакции между шардами становятся вашей заботой.
Перенос живой таблицы: создать партиционированную копию, переливать данные пачками (для массовой вставки из Go подходит CopyFrom в pgx), затем переключить имена в одной транзакции.
Где спотыкаются
Сразу предлагают шардинг, не посмотрев на план запроса. На таблице, которой не хватает индекса, это умножает сложность без выигрыша.
Выбирают ключ, которого нет в типичных запросах. Секций много, а каждый запрос читает их все.
Путают нормализацию с разделением ради скорости. Вынос студентов и курсов в отдельные таблицы убирает дублирование, но не делает большую таблицу оценок меньше.