Najlepszym podejściem do dzielenia tabel MySQL na fragmenty jest nie robienie tego, chyba że jest to całkowicie nieuniknione.
Kiedy piszesz aplikację, zwykle chcesz to zrobić w sposób, który maksymalizuje szybkość i szybkość programisty. Optymalizujesz pod kątem opóźnienia (czas do uzyskania odpowiedzi) lub przepustowości (liczba odpowiedzi na jednostkę czasu) tylko wtedy, gdy jest to konieczne.
Partycjonujesz, a następnie przypisujesz partycje do różnych hostów (= fragmentów) tylko wtedy, gdy suma wszystkich tych partycji nie mieści się już w jednej instancji serwera bazy danych - powodem tego jest albo zapis, albo odczyt.
Przypadek zapisu jest następujący: a) częstotliwość zapisów powoduje trwałe przeciążenie dysków tego serwera lub b) jest wykonywanych zbyt wiele zapisów, co powoduje trwałe opóźnienia replikacji w tej hierarchii replikacji.
Przykładem odczytu dla shardingu jest sytuacja, w której rozmiar danych jest tak duży, że ich zestaw roboczy nie mieści się już w pamięci, a odczyty danych zaczynają trafiać na dysk, zamiast być przez większość czasu obsługiwane z pamięci.
Tylko wtedy, gdy mają do shard to zrobić.
W chwili, gdy odłamki, płacisz za to na wiele sposobów:
Znaczna część twojego SQL nie jest już deklaratywna.
Zwykle w języku SQL mówisz bazie danych, jakie dane chcesz i pozostawiasz optymalizatorowi, aby przekształcił tę specyfikację w program dostępu do danych. To dobrze, ponieważ jest elastyczny, a pisanie takich programów dostępu do danych jest nudną pracą, która szkodzi szybkości.
W środowisku podzielonym na fragmenty prawdopodobnie łączysz tabelę w węźle A z danymi w węźle B lub masz tabelę większą niż węzeł w węzłach A i B i łączysz dane z niej z danymi znajdującymi się w węźle B i C. Zaczynasz ręcznie pisać rozwiązania złączeń oparte na skrótach po stronie aplikacji, aby rozwiązać ten problem (lub wymyślasz na nowo klaster MySQL), co oznacza, że otrzymujesz dużo SQL, które nie są już deklaratywne, ale wyrażają funkcjonalność SQL w sposób proceduralny (np. używasz instrukcji SELECT w pętlach).
Występują duże opóźnienia w sieci.
Zwykle zapytanie SQL można rozwiązać lokalnie, a optymalizator wie o kosztach związanych z dostępem do dysku lokalnego i rozwiązuje zapytanie w sposób minimalizujący związane z tym koszty.
W środowisku podzielonym na fragmenty zapytania są rozwiązywane przez uruchamianie dostępu klucz-wartość w sieci do wielu węzłów (miejmy nadzieję, że w przypadku dostępu do kluczy wsadowych, a nie wyszukiwania pojedynczych kluczy w obie strony) lub przez wypychanie części WHERE
klauzuli dalej do węzłów, gdzie mogą zastosować (to jest nazywane „przesunięciem warunku”), lub oba.
Ale nawet w najlepszych przypadkach wiąże się to z większą liczbą połączeń sieciowych w obie strony niż sytuacja lokalna i jest to bardziej skomplikowane. Zwłaszcza, że optymalizator MySQL nie wie w ogóle nic o opóźnieniach w sieci (Ok, klaster MySQL powoli się w tym poprawia, ale dla zwykłego MySQL poza klastrem jest to nadal prawda).
Tracisz dużo możliwości ekspresji SQL.
Ok, to prawdopodobnie mniej ważne, ale ograniczenia klucza obcego i inne mechanizmy SQL zapewniające integralność danych nie są w stanie objąć wielu fragmentów.
MySQL nie ma API, które pozwala na asynchroniczne zapytania, które są sprawne.
Gdy dane tego samego typu znajdują się w wielu węzłach (np. Dane użytkownika w węzłach A, B i C), zapytania poziome często muszą być rozwiązywane w odniesieniu do wszystkich tych węzłów („Znajdź wszystkie konta użytkowników, które nie były zalogowane od 90 dni albo więcej"). Czas dostępu do danych rośnie liniowo wraz z liczbą węzłów, chyba że można zapytać o wiele węzłów równolegle, a wyniki są agregowane w miarę ich pojawiania się („Map-Reduce”).
Warunkiem wstępnym jest asynchroniczny interfejs komunikacyjny API, który nie istnieje dla MySQL w dobrym stanie. Alternatywą jest dużo rozwidleń i połączeń w procesach potomnych, czyli odwiedzanie świata ssania na przepustce sezonowej.
Po rozpoczęciu fragmentowania struktura danych i topologia sieci stają się widoczne jako punkty wydajności aplikacji. Aby aplikacja działała w miarę dobrze, musi być tego świadoma, a to oznacza, że tak naprawdę tylko fragmentowanie na poziomie aplikacji ma sens.
Pytanie brzmi bardziej, jeśli chcesz automatycznie shardować (na przykład określić, który wiersz trafia do którego węzła, np. Przez haszowanie kluczy podstawowych) lub jeśli chcesz podzielić funkcjonalnie w sposób ręczny („Tabele powiązane z historią użytkownika xyz idą do tego master, podczas gdy tabele związane z abc i def idą do tego mastera ”).
Funkcjonalne fragmentowanie ma tę zaletę, że jeśli zostanie wykonane prawidłowo, przez większość czasu jest niewidoczne dla większości programistów, ponieważ wszystkie tabele związane z ich historią użytkownika będą dostępne lokalnie. To pozwala im jak najdłużej korzystać z deklaratywnego SQL, a także spowoduje mniejsze opóźnienia w sieci, ponieważ liczba transferów między sieciami jest minimalna.
Funkcjonalne fragmentowanie ma tę wadę, że nie pozwala na to, aby żadna pojedyncza tabela była większa niż jedna instancja i wymaga ręcznej uwagi projektanta.
Funkcjonalne fragmentowanie ma tę zaletę, że jest stosunkowo łatwe do wykonania w istniejącej bazie kodu z kilkoma zmianami, które nie są zbyt duże. Witryna http://Booking.com robiła to wiele razy w ciągu ostatnich lat i działała dobrze.
Powiedziawszy to wszystko, patrząc na twoje pytanie, wydaje mi się, że zadajesz niewłaściwe pytania lub całkowicie nie rozumiem twojego stwierdzenia problemu.