La storia della cancellazione fisica di 300 milioni di record in MySQL

Introduzione

Ciao. Sono ningenMe, sviluppatore web.

Come dice il titolo, la mia storia è la storia dell'eliminazione fisica di 300 milioni di record in MySQL.

Mi sono interessato a questo, quindi ho deciso di fare un promemoria (istruzioni).

Casa - Avviso

Il server batch che utilizzo e mantengo ha un processo regolare che raccoglie i dati dell'ultimo mese da MySQL una volta al giorno.

Di solito questo processo viene completato entro circa 1 ora, ma questa volta non è stato completato per 7 o 8 ore e l'avviso non ha smesso di apparire...

Alla ricerca di un motivo

Ho provato a riavviare il processo e a guardare i registri, ma non ho visto nulla di sbagliato.
La query è stata indicizzata correttamente. Ma quando ho pensato a cosa stava andando storto, mi sono reso conto che la dimensione del database è piuttosto grande.

hoge_table | 350'000'000 |

350 milioni di dischi. L'indicizzazione sembrava funzionare correttamente, solo molto lenta.

La raccolta dati richiesta al mese è stata di circa 12 di record. Sembra che il comando di selezione abbia impiegato molto tempo e che la transazione non sia stata eseguita per molto tempo.

DB

Si tratta essenzialmente di una tabella che cresce di circa 400 voci ogni giorno. Il database avrebbe dovuto raccogliere dati solo nell'ultimo mese, quindi ci si aspettava che sopportasse esattamente questa quantità di dati, ma sfortunatamente l'operazione di rotazione non è stata inclusa.

Questo database non è stato sviluppato da me. L'ho preso da un altro sviluppatore, quindi sembrava ancora un debito tecnico.

È arrivato un punto in cui il volume dei dati inseriti quotidianamente è diventato grande e ha finalmente raggiunto il suo limite. Si presume che quando si lavora con una quantità così grande di dati, sarebbe necessario separarli, ma sfortunatamente ciò non è stato fatto.

E poi sono entrato in azione.

Correzione

Era più razionale ridurre le dimensioni del database stesso e ridurre i tempi di elaborazione piuttosto che modificarne la logica stessa.

La situazione dovrebbe cambiare notevolmente se si cancellano 300 milioni di record, quindi ho deciso di farlo... Eh, pensavo che avrebbe sicuramente funzionato.

Azione 1

Dopo aver preparato un backup affidabile, ho finalmente iniziato a inviare richieste.

「Invio di una richiesta」

DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';

"..."

"..."

“Hmm... Nessuna risposta. Forse il processo richiede molto tempo?" — Ho pensato, ma per ogni evenienza ho guardato Grafana e ho visto che il carico del disco stava crescendo molto rapidamente.
"Pericoloso", ho pensato di nuovo e ho immediatamente interrotto la richiesta.

Azione 2

Dopo aver analizzato tutto, mi sono reso conto che il volume dei dati era troppo grande per eliminare tutto in una volta.

Ho deciso di scrivere uno script in grado di eliminare circa 1 di record e l'ho lanciato.

「Implemento lo script」

"Ora funzionerà sicuramente", ho pensato.

Azione 3

Il secondo metodo ha funzionato, ma si è rivelato molto laborioso.
Per fare tutto con attenzione, senza nervi inutili, ci vorrebbero circa due settimane. Tuttavia, questo scenario non soddisfaceva i requisiti del servizio, quindi abbiamo dovuto abbandonarlo.

Quindi ecco cosa ho deciso di fare:

Copia la tabella e rinominala

Dal passaggio precedente, mi sono reso conto che l'eliminazione di una quantità così grande di dati crea un carico altrettanto grande. Quindi ho deciso di creare una nuova tabella da zero utilizzando Inserisci e spostarvi i dati che avrei eliminato.

| hoge_table     | 350'000'000|
| tmp_hoge_table |  50'000'000|

Se imposti alla nuova tabella le stesse dimensioni di cui sopra, anche la velocità di elaborazione dei dati dovrebbe diventare 1/7 più veloce.

Dopo aver creato la tabella e averla rinominata, ho iniziato a utilizzarla come tabella principale. Ora, se lascio cadere la tabella con 300 milioni di record, tutto dovrebbe andare bene.
Ho scoperto che troncare o eliminare crea meno sovraccarico rispetto all'eliminazione e ho deciso di utilizzare questo metodo.

esecuzione

「Invio di una richiesta」

INSERT INTO tmp_hoge_table SELECT FROM hoge_table create_time > 'YYYY-MM-DD HH:MM:SS';

"..."
"..."
"Ehm...?"

Azione 4

Pensavo che l'idea precedente avrebbe funzionato, ma dopo aver inviato la richiesta di inserimento sono comparsi più errori. MySQL non perdona.

Ero già così stanco che ho iniziato a pensare che non volevo più farlo.

Mi sono seduto, ho pensato e ho realizzato che forse c'erano troppe query di inserimento per una volta...
Ho provato a inviare una richiesta di inserimento per la quantità di dati che il database dovrebbe elaborare in 1 giorno. Accaduto!

Bene, dopodiché continueremo a inviare richieste per la stessa quantità di dati. Poiché dobbiamo rimuovere un mese di dati, ripetiamo questa operazione circa 35 volte.

Rinominare una tabella

Qui la fortuna è stata dalla mia parte: tutto è andato liscio.

Avviso scomparso

La velocità di elaborazione batch è aumentata.

Prima questo processo richiedeva circa un'ora, ora ci vogliono circa 2 minuti.

Dopo essere stato sicuro che tutti i problemi fossero stati risolti, ho eliminato 300 milioni di dischi. Ho cancellato la tabella e mi sono sentita rinascere.

Riepilogo

Mi sono reso conto che nell'elaborazione batch mancava l'elaborazione della rotazione e questo era il problema principale. Questo tipo di errore architetturale porta ad una perdita di tempo.

Pensi al carico durante la replica dei dati quando elimini i record dal database? Non sovraccarichiamo MySQL.

Coloro che sono esperti nei database non incontreranno sicuramente un problema del genere. Per il resto di voi, spero che questo articolo sia stato utile.

Grazie per aver letto!

Saremo molto felici se ci dici se questo articolo ti è piaciuto, se la traduzione è chiara, se ti è stato utile?

Fonte: habr.com

Aggiungi un commento