Mysql
 sql >> Database >  >> RDS >> Mysql

Prestazioni MySQL:più tabelle rispetto a indice su una singola tabella e partizioni

Creare 20.000 tabelle è una cattiva idea. Avrai bisogno di 40.000 tavoli in poco tempo, e poi di più.

Ho chiamato questa sindrome Metadata Tribbles nel mio libro SQL Antipatterns . Lo vedi ogni volta che prevedi di creare una "tabella per X" o una "colonna per X".

Ciò causa problemi di prestazioni reali quando si hanno decine di migliaia di tabelle. Ogni tabella richiede a MySQL di mantenere strutture di dati interne, descrittori di file, un dizionario di dati, ecc.

Ci sono anche conseguenze operative pratiche. Vuoi davvero creare un sistema che richieda di creare una nuova tabella ogni volta che un nuovo utente si iscrive?

Ti consiglio invece di utilizzare Partizionamento MySQL .

Ecco un esempio di partizionamento della tabella:

CREATE TABLE statistics (
  id INT AUTO_INCREMENT NOT NULL,
  user_id INT NOT NULL,
  PRIMARY KEY (id, user_id)
) PARTITION BY HASH(user_id) PARTITIONS 101;

Questo ti dà il vantaggio di definire una tabella logica, dividendo anche la tabella in molte tabelle fisiche per un accesso più rapido quando esegui query per un valore specifico della chiave di partizione.

Ad esempio, quando esegui una query come il tuo esempio, MySQL accede solo alla partizione corretta contenente lo specifico user_id:

mysql> EXPLAIN PARTITIONS SELECT * FROM statistics WHERE user_id = 1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: statistics
   partitions: p1    <--- this shows it touches only one partition 
         type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 8
          ref: NULL
         rows: 2
        Extra: Using where; Using index

Il metodo di partizionamento HASH significa che le righe sono poste in una partizione da un modulo della chiave di partizione intera. Ciò significa che molti user_id sono mappati sulla stessa partizione, ma ogni partizione avrebbe in media solo 1/Nesima riga in più (dove N è il numero di partizioni). E definisci la tabella con un numero costante di partizioni, quindi non devi espanderla ogni volta che ottieni un nuovo utente.

Puoi scegliere un numero qualsiasi di partizioni fino a 1024 (o 8192 in MySQL 5.6), ma alcune persone hanno segnalato problemi di prestazioni quando raggiungono un livello così alto.

Si consiglia di utilizzare un numero primo di partizioni. Nel caso in cui i tuoi valori user_id seguano uno schema (come usare solo numeri pari), l'utilizzo di un numero primo di partizioni aiuta a distribuire i dati in modo più uniforme.

Rispondi alle tue domande nei commenti:

Per il partizionamento HASH, se usi 101 partizioni come mostro nell'esempio sopra, ogni partizione ha in media circa l'1% delle tue righe. Hai detto che la tua tabella delle statistiche ha 30 milioni di righe, quindi se usi questo partizionamento, avresti solo 300.000 righe per partizione. Questo è molto più facile da leggere per MySQL. Puoi (e dovresti) usare anche gli indici:ogni partizione avrà il proprio indice e sarà grande solo l'1% come sarebbe l'indice sull'intera tabella non partizionata.

Quindi la risposta a come determinare un numero ragionevole di partizioni è:quanto è grande l'intera tabella e quanto vuoi che siano in media le partizioni?

Il numero di partizioni non deve necessariamente aumentare se si utilizza il partizionamento HASH. Alla fine potresti avere 30 miliardi di righe in totale, ma ho scoperto che quando il tuo volume di dati cresce di ordini di grandezza, ciò richiede comunque una nuova architettura. Se i tuoi dati crescono così tanto, probabilmente hai bisogno di sharding su più server e partizionamento in più tabelle.

Detto questo, puoi ripartizionare una tabella con ALTER TABLE:

ALTER TABLE statistics PARTITION BY HASH(user_id) PARTITIONS 401;

Questo deve ristrutturare la tabella (come la maggior parte delle modifiche di ALTER TABLE), quindi aspettati che ci vorrà del tempo.

Potresti voler monitorare la dimensione dei dati e degli indici nelle partizioni:

SELECT table_schema, table_name, table_rows, data_length, index_length
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE partition_method IS NOT NULL;

Come con qualsiasi tabella, vuoi che la dimensione totale degli indici attivi rientri nel tuo pool di buffer, perché se MySQL deve scambiare parti di indici dentro e fuori dal pool di buffer durante le query SELECT, le prestazioni ne risentono.

Se si utilizza il partizionamento RANGE o LIST, è molto più comune aggiungere, eliminare, unire e dividere le partizioni. Vedere http://dev.mysql. com/doc/refman/5.6/en/partitioning-management-range-list.html

Ti incoraggio a leggere la sezione manuale sul partizionamento , e dai un'occhiata anche a questa bella presentazione:Migliora le prestazioni Con le partizioni MySQL 5.1 .