Най-добрият подход за разделяне на 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 дни или по"). Времето за достъп до данни нараства линейно с броя на възлите, освен ако няколко възли не могат да бъдат запитани паралелно и резултатите да се обобщят при постъпването им („Намаляване на картата“).
Предпоставката за това е API за асинхронна комуникация, който не съществува за MySQL в добра работна форма. Алтернативата е много разклонения и връзки в детските процеси, които посещават света на смученето на сезонна карта.
След като започнете да споделяте, структурата на данните и мрежовата топология стават видими като точки за производителност към вашето приложение. За да работи сравнително добре, приложението ви трябва да е наясно с тези неща, а това означава, че наистина само разделянето на ниво приложение има смисъл.
Въпросът е повече, ако искате да разделите автоматично (определяне кой ред влиза в кой възел чрез хеширане на първични ключове например) или ако искате да разделите функционално по ръчен начин („Таблиците, свързани с потребителската история на xyz, отиват на това master, докато свързаните с abc и def таблици отиват към този главен елемент").
Функционалното разделяне има предимството, че ако се направи правилно, то е невидимо за повечето разработчици през повечето време, тъй като всички таблици, свързани с тяхната потребителска история, ще бъдат достъпни локално. Това им позволява да продължат да се възползват от декларативния SQL възможно най-дълго и също така ще имат по-малко мрежово забавяне, тъй като броят на междумрежовите трансфери е минимален.
Функционалното разделяне има недостатъка, че не позволява нито една таблица да бъде по-голяма от един екземпляр и изисква ръчно внимание от дизайнер.
Функционалното разделяне има предимството, че се прави относително лесно към съществуваща кодова база с редица промени, които не са прекалено големи. http://Booking.com го е правил няколко пъти през последните години и им се е отразило добре.
След като казах всичко това, разглеждайки въпроса ви, вярвам, че задавате грешни въпроси или напълно не разбирам твърдението ви за проблема.