Гісторыя аб фізічным выдаленні 300 мільёнаў запісаў у MySQL

Увядзенне

Прывітанне. Я ningenMe, вэб-распрацоўшчык.

Як сказана ў назве, мая гісторыя - гэта гісторыя пра фізічнае выдаленне 300 мільёнаў запісаў у MySQL.

Я зацікавіўся гэтым, таму вырашыў зрабіць напамінак (інструкцыю).

Пачатак - Alert

У пакетным серверы, які я выкарыстоўваю і абслугоўваю, маецца рэгулярны працэс, які адзін раз у дзень збірае дадзеныя за апошні месяц з MySQL.

Звычайна гэты працэс завяршаецца прыкладна на працягу 1 гадзіны, але ў гэты раз ён не завяршаўся 7 ці 8 гадзін, і alert не пераставаў вылазіць…

Пошук прычыны

Я паспрабаваў перазапусціць працэс, паглядзець логі, але нічога страшнага не ўбачыў.
Запыт індэксаваўся правільна. Але калі я задумаўся, што ідзе ня так, я зразумеў, што аб'ём БД даволі вялікі.

hoge_table | 350'000'000 |

350 мільёнаў запісаў. Здаецца, індэксацыя працавала правільна, проста вельмі марудна.

Патрабаваны збор дадзеных за месяц складаў каля 12 запісаў. Падобна, каманда select заняла шмат часу, і транзакцыя доўгі час не выконвалася.

DB

Па сутнасці гэта табліца, якая кожны дзень павялічваецца прыкладна на 400 000 запісаў. База павінна была збіраць дадзеныя толькі за апошні месяц, такім чынам, разлік быў на тое, што яна будзе вытрымліваць менавіта гэты аб'ём дадзеных, але, нажаль, аперацыя rotate не была ўключаная.

Гэтая база даных была распрацавана не мной. Я прыняў яе ад іншага распрацоўшчыка, таму засталося адчуванне, што гэта тэхнічны абавязак.

Наступіў момант, калі аб'ём штодня якія ўстаўляюцца дадзеных стаў вялікім і, нарэшце, дасягнуў мяжы. Мяркуецца, што працуючы з такім вялікім аб'ёмам дадзеных, трэба было б іх падзяляць, але гэтага, на жаль, не было зроблена.

І тут у справу ўступіў я.

выпраўленне

Было рацыянальна зменшыць саму БД і скараціць час на яе апрацоўку, чым мяняць саму логіку.

Сітуацыя павінна значна змяніцца, калі сцерці 300 мільёнаў запісаў, таму я вырашыў так і зрабіць… Эх, я думаў, што гэта дакладна спрацуе.

Дзеянне 1

Падрыхтаваўшы надзейную рэзервовую копію, я нарэшце пачаў адпраўляць запыты.

「Адпраўка запыту」

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

「…」

「…」

“Хм… Адказу няма. Можа працэс займае шмат часу? - падумаў я, але на ўсякі выпадак зірнуў у grafana і ўбачыў, што загружанасць дыска вельмі хутка расла.
«Небяспечна» - падумаў я яшчэ раз і адразу спыніў запыт.

Дзеянне 2

Прааналізаваўшы ўсё, я зразумеў, што аб'ём дадзеных быў занадта вялікім, каб выдаліць усё за 1 раз.

Я вырашыў напісаць скрыпт, які зможа выдаляць каля 1 запісаў і запусціў яго.

「рэалізую скрыпт」

"Цяпер дакладна спрацуе", - падумаў я

Дзеянне 3

Другі метад спрацаваў, але аказаўся вельмі працаёмкім.
Каб зрабіць усё акуратна, без лішніх нерваў, спатрэбілася б каля двух тыдняў. Але ўсё ж такі сцэнар не адпавядаў сэрвісным патрабаванням, таму прыйшлося ад яго адысці.

Таму, вось што я вырашыў зрабіць:

Капіяваны табліцу і пераназываем

З папярэдняга кроку я зразумеў, што выдаленне такога вялікага аб'ёму дадзеных стварае такую ​​ж вялікую нагрузку. Таму я вырашыў стварыць новую табліцу з нуля з дапамогай insert і ў яе перамясціць даныя, якія збіраўся выдаліць.

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

Калі зрабіць новую табліцу па памеры такую ​​ж, як паказана вышэй, хуткасць апрацоўкі дадзеных таксама павінна стаць на 1/7 хутчэй.

Стварыўшы табліцу і пераназваўшы яе, я пачаў выкарыстоўваць яе як master (асноўную) табліцу. Цяпер, калі я выдалю табліцу з 300 мільёнамі запісаў, усё павінна быць у парадку.
Я даведаўся, што truncate ці drop ствараюць меншую нагрузку, чым delete, і вырашыў выкарыстоўваць гэты спосаб.

выкананне

「Адпраўка запыту」

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

「…」
「…」
「эм…?」

Дзеянне 4

Думаў, папярэдняя ідэя спрацуе, але пасля адпраўкі запыту insert з'явілася шматлікая памылка. MySQL не шкадуе.

Я ўжо так стаміўся, што пачаў думаць, што больш не хачу гэтым займацца.

Пасядзеў-падумаў і зразумеў, што, можа, для аднаго разу запытаў insert было зашмат…
Паспрабаваў адправіць запыт insert на аб'ём даных, якія база павінна апрацоўваць за 1 дзень. Атрымалася!

Ну і пасля гэтага працягваем дасылаць запыты на той жа аб'ём дадзеных. Бо трэба прыбраць месячны аб'ём дадзеных, паўтараем гэтую аперацыю прыкладна 35 раз.

Перайменаванне табліцы

Тут поспех быў на маім баку: усё прайшло гладка.

Alert зніклі

Хуткасць пакетнай апрацоўкі павялічылася.

Раней гэты працэс займаў каля гадзіны, зараз ідзе прыкладна 2 хвіліны.

Пасля таго, як я пераканаўся, што ўсе праблемы вырашаны, я дропнуў 300 запісаў. Я выдаліў табліцу і адчуў сябе нанава народжаным.

Рэзюмаванне

Я зразумеў, што пры пакетнай апрацоўцы быў упушчаны rotate processing, і ў гэтым складалася асноўная праблема. Такая памылка ў архітэктуры прыводзіць да пустога марнавання часу.

А вы задумваецеся аб нагрузцы пры рэплікацыі дадзеных, выдаляючы запісы з базы? Давайце не будзем перагружаць MySQL.

Тыя, хто добра разбіраюцца ў базах даных, з такой праблемай дакладна не сутыкнуцца. А астатнім, спадзяюся, гэты артыкул быў карысны.

Дзякуй за чытанне!

Мы будзем вельмі рады, калі вы раскажаце нам, ці спадабаўся вам дадзены артыкул, ці зразумелы пераклад, ці быў ён вам карысны?

Крыніца: habr.com

Дадаць каментар