L'approccio migliore per lo sharding delle tabelle MySQL non lo fa a meno che non sia totalmente inevitabile farlo.
Quando si scrive un'applicazione, di solito si desidera farlo in modo da massimizzare la velocità, la velocità dello sviluppatore. Ottimizzi la latenza (tempo fino a quando la risposta è pronta) o il throughput (numero di risposte per unità di tempo) solo quando necessario.
Si partiziona e quindi si assegnano le partizioni a host diversi (= frammento) solo quando la somma di tutte queste partizioni non si adatta più a una singola istanza del server di database, il motivo per cui è in scrittura o in lettura.
Il caso di scrittura è a) la frequenza delle scritture sovraccarica i dischi di questo server in modo permanente oppure b) ci sono troppe scritture in corso in modo che la replica ritardi permanentemente in questa gerarchia di replica.
Il caso di lettura per lo sharding è quando la dimensione dei dati è così grande che il working set di essi non si adatta più alla memoria e le letture dei dati iniziano a colpire il disco invece di essere servite dalla memoria la maggior parte del tempo.
Solo quando si ha a coccio voi farlo.
Nel momento in cui dividi, stai pagando per questo in diversi modi:
Gran parte del tuo SQL non è più dichiarativo.
Normalmente, in SQL si dice al database quali dati si desidera e si lascia all'ottimizzatore il compito di trasformare quella specifica in un programma di accesso ai dati. Questa è una buona cosa, perché è flessibile e perché scrivere questi programmi di accesso ai dati è un lavoro noioso che danneggia la velocità.
Con un ambiente frammentato probabilmente stai unendo una tabella sul nodo A ai dati sul nodo B, oppure hai una tabella più grande di un nodo, sui nodi A e B e stai unendo i dati da essa ai dati che si trovano sul nodo B e C. Stai iniziando a scrivere manualmente risoluzioni di join basate su hash lato applicazione per risolverlo (o stai reinventando il cluster MySQL), il che significa che ti ritroverai con un sacco di SQL che non è più dichiarativo, ma esprime la funzionalità SQL in modo procedurale (ad esempio, stai usando le istruzioni SELECT nei cicli).
Stai riscontrando molta latenza di rete.
Normalmente, una query SQL può essere risolta localmente e l'ottimizzatore conosce i costi associati agli accessi al disco locale e risolve la query in modo da ridurre al minimo i costi.
In un ambiente frammentato, le query vengono risolte eseguendo accessi chiave-valore attraverso una rete a più nodi (si spera con accessi chiave in batch e non ricerche di chiavi individuali per round trip) o spingendo parti della WHERE
clausola in avanti nei nodi dove possono essere applicato (che si chiama 'condizione pushdown'), o entrambi.
Ma anche nel migliore dei casi ciò comporta molti più viaggi di andata e ritorno di rete rispetto a una situazione locale, ed è più complicato. Soprattutto perché l'ottimizzatore MySQL non sa nulla della latenza di rete (Ok, il cluster MySQL sta lentamente migliorando in questo, ma per MySQL vanilla al di fuori del cluster questo è ancora vero).
Stai perdendo molta forza espressiva di SQL.
Ok, questo è probabilmente meno importante, ma i vincoli di chiave esterna e altri meccanismi SQL per l'integrità dei dati non sono in grado di estendersi su più frammenti.
MySQL non ha API che consentono query asincrone che funzionano.
Quando i dati dello stesso tipo risiedono su più nodi (ad es. Dati utente sui nodi A, B e C), spesso le query orizzontali devono essere risolte su tutti questi nodi ("Trova tutti gli account utente che non sono stati collegati per 90 giorni o più"). Il tempo di accesso ai dati cresce linearmente con il numero di nodi, a meno che non sia possibile richiedere più nodi in parallelo e i risultati aggregati man mano che arrivano ("Map-Reduce").
La condizione preliminare per questo è un'API di comunicazione asincrona, che non esiste per MySQL in una buona forma funzionante. L'alternativa è un sacco di biforcazioni e connessioni nei processi figlio, che sta visitando il mondo del succhiare con un abbonamento stagionale.
Una volta avviato lo sharding, la struttura dei dati e la topologia di rete diventano visibili come punti di prestazioni per la tua applicazione. Per funzionare ragionevolmente bene, la tua applicazione deve essere consapevole di queste cose, e questo significa che in realtà solo il partizionamento orizzontale a livello di applicazione ha senso.
La domanda è più se vuoi auto-shard (determinare quale riga va in quale nodo eseguendo l'hashing delle chiavi primarie, ad esempio) o se vuoi dividere funzionalmente in modo manuale ("Le tabelle relative alla user story xyz vanno a master, mentre le tabelle relative ad abc e def vanno a quel master ").
Lo sharding funzionale ha il vantaggio che, se fatto correttamente, è invisibile alla maggior parte degli sviluppatori il più delle volte, perché tutte le tabelle relative alla loro storia utente saranno disponibili localmente. Ciò consente loro di trarre vantaggio dall'SQL dichiarativo il più a lungo possibile e incorrerà anche in una minore latenza di rete perché il numero di trasferimenti tra reti è ridotto al minimo.
Il partizionamento orizzontale funzionale ha lo svantaggio di non consentire a una singola tabella di essere più grande di un'istanza e richiede l'attenzione manuale di un designer.
Il partizionamento orizzontale funzionale ha il vantaggio di essere eseguito in modo relativamente semplice su una base di codice esistente con un numero di modifiche non eccessivamente grande. http://Booking.com lo ha fatto più volte negli ultimi anni e ha funzionato bene per loro.
Detto questo, guardando la tua domanda, credo che tu stia facendo le domande sbagliate, o sto completamente fraintendendo la tua dichiarazione del problema.