Historia fizycznego usunięcia 300 milionów rekordów w MySQL

Wprowadzenie

Cześć. Jestem ningenMe, programista stron internetowych.

Jak mówi tytuł, moja historia to historia fizycznego usunięcia 300 milionów rekordów w MySQL.

Zainteresowało mnie to, więc postanowiłem zrobić przypomnienie (instrukcję).

Strona główna - Alarm

Serwer wsadowy, którego używam i utrzymuje, ma regularny proces, który raz dziennie zbiera dane z MySQL za ostatni miesiąc.

Zwykle proces ten kończy się w ciągu około 1 godziny, ale tym razem nie trwał on przez 7 lub 8 godzin, a alert nie przestał się pojawiać...

Znalezienie przyczyny

Próbowałem ponownie uruchomić proces i przejrzeć dzienniki, ale nie zauważyłem niczego złego.
Zapytanie zostało poprawnie zindeksowane. Ale kiedy pomyślałem o tym, co poszło nie tak, zdałem sobie sprawę, że rozmiar bazy danych jest dość duży.

hoge_table | 350'000'000 |

350 milionów rekordów. Indeksowanie wydawało się działać poprawnie, tylko bardzo wolno.

Wymagany miesięczny zbiór danych wynosił około 12 000 000 rekordów. Wygląda na to, że wykonanie polecenia Select zajęło dużo czasu, a transakcja nie została wykonana przez długi czas.

DB

Zasadniczo jest to tabela, która każdego dnia powiększa się o około 400 000 wpisów. Baza miała zbierać dane tylko za ostatni miesiąc, zatem spodziewano się, że wytrzyma dokładnie taką ilość danych, niestety nie uwzględniono operacji rotacji.

Ta baza danych nie została stworzona przeze mnie. Przejąłem go od innego dewelopera, więc nadal czułem, że jest to dług techniczny.

Przyszedł moment, w którym ilość wprowadzanych codziennie danych stała się duża i ostatecznie osiągnęła swój limit. Zakłada się, że przy pracy z tak dużą ilością danych konieczne byłoby ich rozdzielenie, czego niestety nie zrobiono.

I wtedy przystąpiłem do działania.

Korekta

Bardziej racjonalne było zmniejszenie rozmiaru samej bazy danych i skrócenie czasu jej przetwarzania, niż zmiana samej logiki.

Sytuacja powinna znacząco się zmienić, jeśli usunie się 300 milionów rekordów, więc zdecydowałem się to zrobić... Ech, myślałem, że to na pewno zadziała.

Działanie 1

Po przygotowaniu niezawodnej kopii zapasowej w końcu zacząłem wysyłać żądania.

「Wysyłanie zapytania」

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

„…”

„…”

„Hmm... Brak odpowiedzi. Może proces ten zajmuje dużo czasu?” — pomyślałem, ale na wszelki wypadek zajrzałem do grafany i zobaczyłem, że obciążenie dysku rośnie bardzo szybko.
„Niebezpieczne” – pomyślałem ponownie i natychmiast przerwałem prośbę.

Działanie 2

Po przeanalizowaniu wszystkiego zdałem sobie sprawę, że ilość danych jest zbyt duża, aby usunąć wszystko na raz.

Postanowiłem napisać skrypt, który mógłby usunąć około 1 000 000 rekordów i uruchomiłem go.

「Wdrażam scenariusz」

„Teraz na pewno się uda” – pomyślałem.

Działanie 3

Druga metoda zadziałała, ale okazała się bardzo pracochłonna.
Zrobienie wszystkiego ostrożnie, bez zbędnych nerwów zajęłoby około dwóch tygodni. Ale nadal ten scenariusz nie spełniał wymagań usługi, więc musieliśmy od niego odejść.

Oto co postanowiłem zrobić:

Skopiuj tabelę i zmień jej nazwę

Z poprzedniego kroku zdałem sobie sprawę, że usunięcie tak dużej ilości danych powoduje równie duże obciążenie. Postanowiłem więc utworzyć od zera nową tabelę za pomocą wstawiania i przenieść do niej dane, które miałem zamiar usunąć.

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

Jeśli nowa tabela będzie miała taki sam rozmiar jak powyżej, prędkość przetwarzania danych powinna również wzrosnąć o 1/7.

Po utworzeniu tabeli i zmianie jej nazwy zacząłem używać jej jako tabeli głównej. Teraz, jeśli opuszczę tabelę zawierającą 300 milionów rekordów, wszystko powinno być w porządku.
Dowiedziałem się, że obcięcie lub upuszczenie powoduje mniejsze obciążenie niż usunięcie i zdecydowałem się zastosować tę metodę.

Wydajność

「Wysyłanie zapytania」

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

„…”
„…”
„Em…?”

Działanie 4

Myślałem, że poprzedni pomysł zadziała, ale po wysłaniu prośby o wstawienie pojawiło się wiele błędów. MySQL nie wybacza.

Byłam już tak zmęczona, że ​​zaczęłam myśleć, że nie chcę już tego robić.

Usiadłem, pomyślałem i zdałem sobie sprawę, że może było zbyt wiele zapytań o wstawienie na raz…
Próbowałem wysłać prośbę o wstawienie ilości danych, które baza danych powinna przetworzyć w ciągu 1 dnia. Stało się!

Cóż, potem nadal wysyłamy żądania dotyczące tej samej ilości danych. Ponieważ musimy usunąć dane z miesiąca, powtarzamy tę operację około 35 razy.

Zmiana nazwy tabeli

Tutaj szczęście było po mojej stronie: wszystko poszło gładko.

Alarm zaginął

Zwiększono prędkość przetwarzania wsadowego.

Wcześniej proces ten zajmował około godziny, teraz zajmuje około 2 minut.

Gdy upewniłem się, że wszystkie problemy zostały rozwiązane, usunąłem 300 milionów rekordów. Usunąłem stół i poczułem się narodzony na nowo.

Streszczenie

Zdałem sobie sprawę, że w przetwarzaniu wsadowym brakuje przetwarzania rotacyjnego i to był główny problem. Tego rodzaju błędy architektoniczne prowadzą do straty czasu.

Czy myślisz o obciążeniu podczas replikacji danych podczas usuwania rekordów z bazy danych? Nie przeciążajmy MySQL.

Osoby dobrze zorientowane w bazach danych na pewno nie spotkają się z takim problemem. Mam nadzieję, że ten artykuł był przydatny dla pozostałych.

Dziękuje za przeczytanie!

Będzie nam bardzo miło, jeśli powiesz nam, czy podobał Ci się ten artykuł, czy tłumaczenie jest jasne, czy było dla Ciebie przydatne?

Źródło: www.habr.com

Dodaj komentarz