Introduzione
Ciao. Sono ningenMe, sviluppatore web.
Come suggerisce il titolo, la mia storia riguarda l'eliminazione fisica di 300 milioni di record in MySQL.
Mi sono interessato a questo, quindi ho deciso di creare una guida (istruzione).
Inizio — Alert
In batch server, che utilizzo e gestisco, c'è un processo regolare che raccoglie dati dell'ultimo mese da MySQL una volta al giorno.
Di solito, questo processo si completa in circa 1 ora, ma questa volta ha impiegato 7 o 8 ore e l'alert non smetteva di apparire...
Cercare la causa
Ho provato a riavviare il processo, a controllare i log, ma non ho visto nulla di preoccupante.
La query era indicizzata correttamente. Ma quando mi sono chiesto cosa non andasse, ho capito che il volume del database era piuttosto grande.
hoge_table | 350'000'000 |350 milioni di record. Sembra che l'indicizzazione funzionasse correttamente, semplicemente molto lentamente.
La raccolta di dati richiesta per il mese era di circa 12.000.000 di record. Sembra che la query select abbia richiesto molto tempo e la transazione non si sia completata a lungo.
DB
Fondamentalmente, è una tabella che cresce ogni giorno di circa 400.000 record. Il database doveva raccogliere i dati solo dell'ultimo mese, quindi era previsto che gestisse solo questo volume di dati, ma, sfortunatamente, l'operazione rotate non era attivata.
Questo database non è stato progettato da me. L'ho preso da un altro sviluppatore, quindi è rimasta la sensazione di un debito tecnico.
È arrivato un momento in cui il volume dei dati inseriti quotidianamente è diventato troppo grande e ha finalmente raggiunto il limite. Si presume che, lavorando con un volume di dati così grande, si debbano dividere, ma purtroppo ciò non è stato fatto.
Ed è qui che sono intervenuto.
Correzione
Era più razionale ridurre il database stesso e ridurre il tempo di elaborazione piuttosto che cambiare la logica stessa.
La situazione dovrebbe cambiare notevolmente se cancellassimo 300 milioni di record, quindi ho deciso di procedere… Ah, pensavo che questo sicuramente avrebbe funzionato.
Azione 1
Dopo aver preparato un backup affidabile, ho finalmente iniziato a inviare le query.
「Invio della query」
DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';「…」
「…」
“Hmm… Nessuna risposta. Forse il processo richiede molto tempo?” — pensai, ma per sicurezza controllai Grafana e vidi che il carico del disco stava aumentando rapidamente.
“Pericoloso” — pensai di nuovo e fermai subito la query.
Azione 2
Dopo aver analizzato tutto, ho capito che il volume dei dati era troppo grande per eliminare tutto in una sola volta.
Ho deciso di scrivere uno script che potesse eliminare circa 1.000.000 di record e l'ho avviato.
「Implemento lo script」
“Ora sicuramente funzionerà”, pensai.
Azione 3
Il secondo metodo ha funzionato, ma era molto laborioso.
Per fare tutto in modo accurato, senza stress inutili, ci sarebbero volute circa due settimane. Ma questo scenario non rispettava i requisiti di servizio, quindi ho dovuto abbandonarlo.
Quindi, ecco cosa ho deciso di fare:
Copiamo la tabella e la rinominiamo
Dal passo precedente ho capito che l'eliminazione di un volume così grande di dati crea un carico altrettanto grande. Quindi ho deciso di creare una nuova tabella da zero usando insert e spostarci i dati che intendevo eliminare.
| hoge_table | 350'000'000|
| tmp_hoge_table | 50'000'000|Se crei una nuova tabella della stessa dimensione di quella sopra, la velocità di elaborazione dei dati dovrebbe anche essere 1/7 più veloce.
Creando la tabella e rinominandola, ho iniziato a usarla come tabella master. Ora, se elimino la tabella con 300 milioni di record, tutto dovrebbe andare bene.
Ho scoperto che truncate o drop creano un carico minore rispetto a delete e ho deciso di usare questo metodo.
Esecuzione
「Invio della query」
INSERT INTO tmp_hoge_table SELECT FROM hoge_table WHERE create_time > 'YYYY-MM-DD HH:MM:SS'; 「…」
「…」
「Eh…?」
Azione 4
Pensavo che l'idea precedente avrebbe funzionato, ma dopo aver inviato la query insert sono comparsi vari errori. MySQL non perdona.
Ero così stanco che ho cominciato a pensare che non volessi farlo più.
Ho riflettuto e ho capito che, forse, per una volta c'erano troppi insert.
Ho provato a inviare una query insert per il volume di dati che il database doveva elaborare in un giorno. Ce l'ho fatta!
E dopo questo ho continuato a inviare query per lo stesso volume di dati. Poiché dovevo rimuovere il volume mensile di dati, ho ripetuto questa operazione circa 35 volte.
Rinominare la tabella
Qui la fortuna è stata dalla mia parte: è andato tutto liscio.
Gli alert sono scomparsi.
La velocità di elaborazione batch è aumentata.
In precedenza, questo processo richiedeva circa un'ora, ora ci vogliono circa 2 minuti.
Dopo essermi assicurato che tutti i problemi fossero risolti, ho eliminato 300 milioni di record. Ho cancellato la tabella e mi sono sentito rinato.
Riepilogo
Ho capito che nella elaborazione in batch era stata trascurata la rotazione, e questo era il problema principale. Un errore di questo tipo nell'architettura porta a una perdita di tempo inutile.
Ti preoccupa il carico durante la replicazione dei dati quando elimini le voci dal database? Evitiamo di sovraccaricare MySQL.
Coloro che hanno una buona conoscenza dei database sicuramente non si imbatteranno in questo problema. Spero che questo articolo sia stato utile per gli altri.
Grazie per la lettura!
Saremmo molto felici se ci dicessi se ti è piaciuto questo articolo, se la traduzione è chiara e se ti è stata utile.
Fonte: habr.com
