O poveste despre ștergerea fizică a 300 de milioane de înregistrări în MySQL

Introducere

Salut. Sunt ningenMe, dezvoltator web.

Așa cum se spune în titlu, povestea mea este despre eliminarea fizică a 300 de milioane de înregistrări din MySQL.

M-am interesat de acest subiect, așa că am decis să fac un ghid (instrucțiuni).

Început — Alert

În modul batch server, pe care îl folosesc și întrețin, există un proces regulat care colectează datele din ultima lună din MySQL, o dată pe zi.

De obicei, acest proces se finalizează în aproximativ 1 oră, dar de data aceasta nu s-a terminat timp de 7 sau 8 ore, iar alertul continua să apară...

Căutarea cauzei

Am încercat să repornesc procesul, să verific jurnalele, dar nu am observat nimic grav.
Interogarea s-a indexat corect. Dar când m-am gândit ce ar putea merge prost, mi-am dat seama că dimensiunea bazei de date este destul de mare.

hoge_table | 350'000'000 |

350 de milioane de înregistrări. Se pare că indexarea a funcționat corect, doar că foarte lent.

Colectarea datelor lunare era de aproximativ 12.000.000 de înregistrări. Se pare că comenzile select au durat mult timp, iar tranzacția nu s-a finalizat mult timp.

DB

Practic, este o tabelă care crește zilnic cu aproximativ 400.000 de înregistrări. Baza de date ar fi trebuit să colecteze date doar pentru ultima lună, deci se presupunea că va gestiona exact acest volum de date, dar, din păcate, operațiunea de rotire nu a fost activată.

Această bază de date nu a fost dezvoltată de mine. Am primit-o de la un alt dezvoltator, așa că am rămas cu senzația că este o datorie tehnică.

A sosit momentul în care volumul de date inserate zilnic a devenit mare și, în final, a atins limita. Se presupune că lucrând cu un volum atât de mare de date, ar fi trebuit să le segmentăm, dar din păcate, acest lucru nu s-a întâmplat.

Și aici interveni eu.

Corectare

A fost mai rațional să reduc bază de date în sine și să scad timpul de procesare, decât să schimb logica în sine.

Situația ar trebui să se schimbe semnificativ dacă aș șterge 300 de milioane de înregistrări, așa că am decis să fac exact asta... Ah, am crezut că va funcționa cu siguranță.

Acțiunea 1

După ce am pregătit un backup solid, în sfârșit am început să trimit interogările.

「Trimitere interogare」

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

「…」

「…」

“Hmm... Nu am primit răspuns. Poate procesul durează mult?” — m-am gândit, dar, de fiecare dată, am verificat în grafana și am observat că încărcarea discului creștea foarte repede.
„Ceva periculos” – m-am gândit din nou și imediat am oprit cererea.

Acțiunea 2

Analizând totul, am realizat că volumul de date era prea mare pentru a șterge totul dintr-o dată.

Am decis să scriu un script care să poată șterge aproximativ 1.000.000 de înregistrări și l-am lansat.

「îmi voi implementa scriptul」

„Acum cu siguranță va funcționa”, m-am gândit.

Acțiunea 3

A doua metodă a funcționat, dar s-a dovedit a fi foarte laborioasă.
Pentru a face totul cu atenție, fără nervi în plus, ar fi fost nevoie de aproximativ două săptămâni. Totuși, acest scenariu nu corespundea cerințelor de servicii, așa că a trebuit să renunț la el.

Așa că, iată ce am decis să fac:

Copiem tabelul și îl redenumim.

Din pasul anterior, am înțeles că ștergerea unui astfel de volum mare de date creează o astfel de sarcină mare. De aceea, am decis să creez un nou tabel de la zero folosind inserții și să mut datele pe care intenționam să le șterg.

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

Dacă creăm un nou tabel de dimensiuni identice cu cele menționate mai sus, viteza de procesare a datelor ar trebui să fie cu 1/7 mai rapidă.

După ce am creat tabelul și l-am redenumit, am început să-l folosesc ca tabel principal. Acum, dacă elimin tabelul cu 300 de milioane de înregistrări, totul ar trebui să fie în regulă.
Am aflat că truncate sau drop generează o sarcină mai mică decât delete și am decis să folosesc această metodă.

Execuție

「Trimitere interogare」

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

「…」
「…」
「eh…?」

Acțiunea 4

Am crezut că ideea anterioară va funcționa, dar după trimiterea cererii de inserare a apărut o multitudine de erori. MySQL nu face rabat.

Eram deja atât de obosit încât am început să cred că nu mai vreau să mă ocup de asta.

M-am gândit și am realizat că poate au fost prea multe cereri de inserare pentru o singură dată…
Am încercat să trimit o cerere de inserare pentru volumul de date pe care baza ar trebui să-l proceseze într-o singură zi. A mers!

Ei bine, după asta continuăm să trimitem cereri pentru același volum de date. Deoarece trebuie să eliminăm volumul de date lunar, repetăm această operație de aproximativ 35 de ori.

Redenumirea tabelului

Aici norocul a fost de partea mea: totul a decurs lin.

Alerta a dispărut.

Viteza de procesare în lot a crescut.

Anterior, acest proces dura aproximativ o oră, acum durează aproximativ 2 minute.

După ce m-am asigurat că toate problemele sunt rezolvate, am eliminat 300 de milioane de înregistrări. Am șters tabelul și m-am simțit ca și cum m-aș fi născut din nou.

Rezumat

Am realizat că, în procesarea în loturi, a fost omis procesul de rotire, iar aceasta a fost problema principală. O astfel de eroare în arhitectură duce la o pierdere de timp inutil.

Te gândești la sarcina de lucru în timpul replicării datelor, atunci când ștergi înregistrări din baza de date? Să nu suprasolicităm MySQL.

Cei care au cunoștințe solide despre baze de date nu se vor confrunta cu o astfel de problemă. Sper că acest articol a fost util celorlalți.

Thank you for reading!

Am fi foarte bucuroși dacă ne-ai povesti dacă ți-a plăcut acest articol, dacă traducerea a fost clară și dacă ți-a fost de folos?

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster