Какие есть стратегии шардирования и партиционирования таблиц в базе данных?
Что проверяют
Различаете ли вы партиционирование внутри одной базы и шардирование между серверами и понимаете ли, что ключ разбиения выбирают по запросам, а не по структуре таблицы. Следом обычно спрашивают, что делать с запросами, которым нужны данные из нескольких шардов.
Как отвечать
Партиционирование делит таблицу на секции в одном экземпляре СУБД. В PostgreSQL декларативно, трёх видов:
- RANGE: по диапазону, чаще по дате. Старые данные уходят через
DETACH PARTITIONиDROP TABLEмгновенно, без огромногоDELETE; - LIST: по перечню значений, например по региону;
- HASH: по хэшу ключа, когда нужен равномерный разброс без естественных диапазонов.
Выигрыш даёт partition pruning: если в WHERE есть ключ партиционирования, планировщик читает только нужные секции. Ограничение: первичный ключ и уникальные индексы обязаны включать этот ключ.
Шардирование разносит данные по серверам, и главное здесь выбор ключа и схемы маршрутизации:
- по хэшу:
hash(user_id) % Nраспределяет ровно, но при смене N переезжает почти всё. Спасают консистентное хэширование или заранее нарезанные виртуальные шарды; - по диапазону: легко добавлять шарды, но свежие данные создают горячую точку;
- по справочнику: отдельный сервис хранит соответствие ключа и шарда. Гибко, но это ещё одна точка отказа;
- географическое: данные ближе к пользователю и в нужной юрисдикции.
Со стороны Java маршрутизацию делают в приложении через AbstractRoutingDataSource в Spring, прозрачно через Apache ShardingSphere или снаружи, средствами Citus для PostgreSQL и Vitess для MySQL.
Где спотыкаются
Выбирают ключ с низкой кардинальностью или поле, которого нет в большинстве запросов. В итоге каждый запрос идёт на все шарды.
Называют вынос колонок в отдельную таблицу «вертикальным шардированием» и забывают про межшардовые операции: JOIN, агрегаты, транзакции. Транзакцию через два шарда придётся делать сагой или 2PC, и лучше сказать об этом до того, как спросят.
Оставляют автоинкремент в роли идентификатора. На нескольких шардах он даст дубли, нужны UUIDv7, ID в духе Snowflake или выделенные диапазоны.