Come convertire una tabella di righe 66.862.521 da MyISAM a InnoDB senza andare offline per diverse ore?


18

è possibile (e come) convertire una grande tabella MyISAM in InnoDB senza portare l'applicazione offline. Richiede di inserire un paio di righe in quella tabella ogni secondo, ma è possibile sospenderlo per circa 2 minuti.

Ovviamente ALTER TABLE ... engine = innodb non funzionerà. Perciò avevo il piano di creare una nuova tabella con il motore innodb e di copiarne il contenuto. E alla fine, sospendi il thread del registro dell'applicazione e RENAME TABLE.

Sfortunatamente anche fare la copia in piccoli lotti di 100 righe genera un ritardo significativo dopo qualche tempo.

Modifica : le righe esistenti non vengono mai modificate, questa tabella viene utilizzata per la registrazione.



3
Bene, quella domanda riguarda la riduzione al minimo del tempo di conversazione. Non mi importa se le conversazioni richiedono un paio di giorni o settimane. Ma deve funzionare in background senza richiedere tempi di inattività dell'applicazione e senza creare un notevole ritardo.
Hendrik Brummermann,

Risposte:


15

Creare un'impostazione Master-Master come segue:

  • Crea secondo master, MasterB
  • MasterB funge da slave per logTable
  • Crea logTable_newcome innodb
  • Esegui INSERT INTO logTable_new SELECT * FROM logTable(psuedocode) su MasterB, che invia la replica a MasterA
  • Quando logTable_newMasterA termina la sincronizzazione, scambia le tabelle

10

Dato il vincolo di:

Non mi importa se le conversazioni richiedono un paio di giorni o settimane. Ma deve funzionare in background senza richiedere tempi di inattività dell'applicazione e senza creare un notevole ritardo

Mentre esegui la registrazione, se hai un buon modo per impostare un marcatore in modo da poter dire a cosa inizi il processo, quindi puoi riapplicare qualsiasi registro o fare in modo che i registri vengano scritti in un file di testo in modo successivamente puoi ingerirli con LOAD DATA INFILE

Parte del problema è che scrivere in batch più piccoli significa che gli indici devono essere ricalcolati più e più volte; farai meglio a eseguirlo tutto in una volta, ma questo potrebbe causare un ritardo 'evidente' sul sistema .. ma non devi farlo sul tuo server di produzione.

  1. Metti in pausa la registrazione o imposta alcuni marker in modo da poter riapplicare i log da questo punto in poi.
  2. Copia la tua tabella MyISM su un altro sistema
  3. Sull'altro sistema, crea una tabella InnoDB con un nome diverso e migra i dati (potrebbe anche essere più veloce scaricarli e usarli LOAD DATA INFILE)
  4. Copia la tabella InnoDB di nuovo nel sistema originale
  5. Impostare un altro marcatore per la registrazione.
  6. Riapplica tutti i registri alla nuova tabella tra gli ultimi due marcatori.
  7. (ripetere i passaggi 5 e 6 se il passaggio 6 richiede più di un minuto circa, fino a quando mancano solo pochi secondi)
  8. Scambia i tavoli (rinomina quello vecchio in table_BACKUP, quello nuovo sotto il nome di quello vecchio)
  9. Recupera i registri dall'ultimo marcatore.

9

Sfortunatamente anche fare la copia in piccoli lotti di 100 righe genera un ritardo significativo dopo qualche tempo.

Stai aggiungendo qualche ritardo tra ogni batch o stai semplicemente raggruppando gli aggiornamenti ed eseguendo ogni batch direttamente dopo quello precedente?

In tal caso, prova a creare script per la conversione nella tua lingua preferita con qualcosa del tipo:

repeat
    copy oldest 100 rows that haven't been copied yet to new table
    sleep for as long as that update took
until there are <100 rows unprocessed
stop logging service
move the last few rows
rename tables
restart logging
delete the old table when you are sure the conversion has worked

Ciò dovrebbe garantire che la conversione non richieda più o meno della metà della capacità del server, anche tenendo conto delle differenze di carico imposte dal momento che l'utilizzo del sistema varia nel tempo.

O se si desidera utilizzare quanto più tempo possibile quando il servizio è relativamente inattivo ma arretrare (potenzialmente in pausa per un certo periodo di tempo) quando il database deve fare un po 'di lavoro per i propri utenti, sostituirlo sleep for as long as the update tookcon if the server's load is above <upper measure>, sleep for some seconds then check again, loop around the sleep/check until the load drops below <lower measure>. Ciò significa che può andare avanti a vapore in tempi tranquilli ma si interromperà completamente quando il server è occupato a eseguire il normale carico di lavoro. La determinazione del carico dipenderà dal tuo sistema operativo: in Linux e simili dovrebbe valere il valore medio del carico di 1 minuto /proc/loadavgo l'output di uptime. <lower measure>e <upper measure>può avere lo stesso valore, anche se è normale che i controlli di questo tipo abbiano una differenza, in modo che il processo non continui a iniziare, quindi a mettere immediatamente in pausa a causa del suo riavvio che ha un'influenza sulla misura del carico.

Ovviamente questo non funzionerebbe per le tabelle in cui le vecchie righe possono essere modificate, ma funzionerà bene per una tabella di registro come quella che descrivi.

In questo caso, vorrai ignorare la solita saggezza della creazione di indici dopo aver popolato la nuova tabella. Mentre questo è davvero più efficiente quando vuoi che le cose siano il più velocemente possibile (l'effetto sul resto del sistema sia dannato), in questo caso non vuoi il grande eccesso di carico alla fine del processo come il gli indici sono completamente creati in una volta sola poiché questo è un processo che non puoi mettere in pausa quando le cose si fanno impegnate.


4

Qualcosa del genere funzionerebbe?

  1. Metti in pausa la registrazione (quindi la $auto_incrementtabella di registrazione mytable non cambia).
  2. Nota il $auto_incrementvalore usando SHOW TABLE STATUS LIKE 'mytable'.
  3. CREATE TABLE mytable_new LIKE mytable
  4. ALTER TABLE mytable_new AUTO_INCREMENT=$auto_increment ENGINE=Innodb
  5. RENAME TABLE mytable TO mytable_old, mytable_new TO mytable
  6. Abilita di nuovo la registrazione. La tabella Innodb ora inizierà a popolarsi.
  7. INSERT INTO mytable SELECT * FROM mytable_old.

È possibile eseguire il passaggio 7 in batch o in un'istruzione poiché non dovrebbe bloccare la registrazione normale.


sarebbe ancora bloccante, a causa del modo in cui innodb gestisce auto_increment. per impostazione predefinita, innodb accetta un blocco a livello di tabella quando viene inserito in una colonna auto_increment e rilascia il blocco non appena termina l'inserimento.
ovais.tariq,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.