Лучший подход к сегментированию таблиц MySQL - не делать этого, если это не является совершенно неизбежным.
Когда вы пишете приложение, вы обычно хотите сделать это таким образом, чтобы максимизировать скорость, скорость разработчика. Вы оптимизируете задержку (время до того, как ответ будет готов) или пропускную способность (количество ответов в единицу времени) только при необходимости.
Вы разделяете, а затем назначаете разделы различным хостам (= сегменту) только тогда, когда сумма всех этих разделов больше не умещается на одном экземпляре сервера базы данных - причина этого либо в записи, либо в чтении.
Случай записи: а) частота операций записи приводит к постоянной перегрузке дисков этого сервера или б) выполняется слишком много операций записи, поэтому репликация постоянно отстает в этой иерархии репликации.
Случай чтения для сегментирования - это когда размер данных настолько велик, что их рабочий набор больше не помещается в память, а считываемые данные начинают попадать на диск вместо того, чтобы большую часть времени обслуживаться из памяти.
Вы делаете это только тогда, когда вам нужно осколить.
В момент создания шарда вы платите за это несколькими способами:
Большая часть вашего SQL больше не декларативна.
Обычно в SQL вы сообщаете базе данных, какие данные вам нужны, и оставляете оптимизатору превратить эту спецификацию в программу доступа к данным. Это хорошо, потому что это гибко, и потому что написание этих программ доступа к данным - скучная работа, которая вредит скорости.
В сегментированной среде вы, вероятно, объединяете таблицу на узле A с данными на узле B, или у вас есть таблица размером больше, чем узел, на узлах A и B, и вы объединяете данные из нее с данными, которые находятся на узлах B и C. Вы начинаете писать разрешения соединения на основе хэшей на стороне приложения вручную, чтобы решить эту проблему (или вы заново изобретаете кластер MySQL), что означает, что вы получаете много SQL, который больше не декларативен, но выражает функциональность SQL процедурным способом (например, вы используете операторы SELECT в циклах).
У вас большая задержка в сети.
Обычно SQL-запрос может быть разрешен локально, и оптимизатор знает о затратах, связанных с доступом к локальному диску, и разрешает запрос таким образом, чтобы минимизировать затраты на это.
В сегментированной среде запросы разрешаются либо путем выполнения доступов по ключу по сети к нескольким узлам (надеюсь, с пакетным доступом по ключам, а не индивидуальным поиском ключей за круговой обход), либо путем передачи частей WHERE
предложения на узлы, где они могут быть примененным (это называется «выталкивание условия») или и то, и другое.
Но даже в лучшем случае это включает в себя намного больше сетевых обходов, чем локальная ситуация, и это более сложно. Тем более, что оптимизатор MySQL вообще ничего не знает о задержках в сети (хорошо, кластер MySQL постепенно улучшается в этом, но для ванильного MySQL вне кластера это все еще верно).
Вы теряете выразительную силу SQL.
Хорошо, это, вероятно, менее важно, но ограничения внешнего ключа и другие механизмы SQL для целостности данных не могут охватывать несколько сегментов.
MySQL не имеет API, который разрешает асинхронные запросы в рабочем состоянии.
Когда данные одного и того же типа находятся на нескольких узлах (например, пользовательские данные на узлах A, B и C), горизонтальные запросы часто необходимо разрешать для всех этих узлов («Найти все учетные записи пользователей, которые не входили в систему в течение 90 дней. или больше"). Время доступа к данным растет линейно с количеством узлов, если только несколько узлов не могут быть запрошены параллельно, а результаты агрегированы по мере их поступления («Map-Reduce»).
Предварительным условием для этого является асинхронный коммуникационный API, который не существует для MySQL в хорошей рабочей форме. Альтернативой является множество разветвлений и соединений в дочерних процессах, которые посещают мир suck по сезонному абонементу.
Как только вы начнете сегментирование, структура данных и топология сети станут видимыми как точки производительности вашего приложения. Чтобы работать достаточно хорошо, ваше приложение должно знать об этих вещах, а это означает, что в действительности имеет смысл только сегментирование на уровне приложения.
Вопрос в том, хотите ли вы автоматически сегментировать (определение того, какая строка входит в какой узел, например, путем хеширования первичных ключей) или если вы хотите функционально разделить вручную («Таблицы, относящиеся к пользовательской истории xyz, переходят к этому master, а таблицы, связанные с abc и def, переходят к этому мастеру ").
Функциональное сегментирование имеет то преимущество, что, если все сделано правильно, большую часть времени оно невидимо для большинства разработчиков, потому что все таблицы, связанные с их пользовательской историей, будут доступны локально. Это позволяет им по-прежнему извлекать выгоду из декларативного SQL как можно дольше, а также снижает задержку в сети, поскольку количество межсетевых передач остается минимальным.
Функциональное сегментирование имеет тот недостаток, что он не позволяет отдельной таблице быть больше одного экземпляра и требует ручного внимания дизайнера.
Функциональное сегментирование имеет то преимущество, что оно относительно легко выполняется с существующей кодовой базой с некоторыми изменениями, которые не являются слишком большими. http://Booking.com делал это несколько раз за последние годы, и у них это хорошо сработало.
Сказав все это, глядя на ваш вопрос, я действительно считаю, что вы задаете неправильные вопросы, или я полностью не понимаю вашу постановку проблемы.