Kisah penghapusan fisik 300 juta catatan di MySQL

pengantar



Hei. Saya ningenMe, seorang pengembang web.



Seperti judulnya, cerita saya tentang menghapus 300 juta catatan di MySQL secara fisik.



Saya menjadi tertarik dengan hal ini, jadi saya memutuskan untuk membuat memo (instruksi).



Mulai - Waspada



Server batch yang saya gunakan dan pelihara memiliki proses reguler yang mengumpulkan data selama sebulan terakhir dari MySQL sekali sehari.



Biasanya proses ini selesai dalam waktu sekitar 1 jam, tetapi kali ini tidak selesai selama 7 atau 8 jam, dan peringatan tidak pernah berhenti keluar ...



Mencari suatu alasan



Saya mencoba untuk memulai kembali proses, melihat log, tetapi saya tidak melihat ada yang buruk.

Permintaan tersebut diindeks dengan benar. Tetapi ketika saya bertanya-tanya apa yang salah, saya menyadari bahwa ukuran database cukup besar.



hoge_table | 350'000'000 |


350 juta catatan. Pengindeksan tampaknya bekerja dengan benar, hanya saja sangat lambat.



Pengumpulan data yang diperlukan per bulan adalah sekitar 12.000.000 catatan. Sepertinya perintah pilih membutuhkan waktu lama dan transaksi tidak dijalankan dalam waktu lama.



DB



Pada dasarnya, ini adalah tabel yang tumbuh sekitar 400.000 rekaman setiap hari. Basis data seharusnya mengumpulkan data hanya untuk bulan lalu, oleh karena itu, perhitungannya didasarkan pada fakta bahwa ia akan menahan jumlah data ini dengan tepat, tetapi, sayangnya, operasi rotasi tidak disertakan.



Database ini tidak saya kembangkan. Saya mengambil alihnya dari pengembang lain, jadi ini terasa seperti utang teknis.



Momennya tiba ketika jumlah data yang dimasukkan setiap hari menjadi besar dan akhirnya mencapai batasnya. Diasumsikan bahwa bekerja dengan data dalam jumlah besar, akan perlu untuk memisahkannya, tetapi sayangnya, ini tidak dilakukan.



Dan kemudian saya masuk.



Koreksi



Lebih rasional untuk mengurangi database itu sendiri dan mengurangi waktu pemrosesannya daripada mengubah logika itu sendiri.



Situasinya akan berubah secara signifikan jika 300 juta rekaman dihapus, jadi saya memutuskan untuk melakukannya ... Eh, saya pikir itu pasti akan berhasil.



Langkah 1



Setelah menyiapkan cadangan yang andal, saya akhirnya mulai mengirimkan permintaan.



「Mengirimkan permintaan」



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


「...」



「...」



“Hmm ... Tidak ada jawaban. Mungkin prosesnya memakan waktu lama? " - Saya pikir, tapi kalau-kalau saya melihat di grafana dan melihat bahwa beban disk bertambah dengan sangat cepat.

"Berbahaya" - Saya berpikir lagi dan segera menghentikan permintaan.



Langkah 2



Setelah menganalisis semuanya, saya menyadari bahwa jumlah data terlalu besar untuk menghapus semuanya sekaligus.



Saya memutuskan untuk menulis skrip yang dapat menghapus sekitar 1.000.000 catatan dan menjalankannya.



「Saya menerapkan skrip」



"Sekarang pasti akan berhasil," pikir saya



LANGKAH 3



Metode kedua berhasil, tetapi terbukti sangat memakan waktu.

Butuh waktu sekitar dua minggu untuk mengerjakan semuanya dengan rapi, tanpa rasa gugup. Tapi tetap saja, skenario ini tidak memenuhi persyaratan layanan, jadi saya harus menjauh darinya.



Karena itu, inilah yang saya putuskan untuk lakukan:



Salin tabel dan ganti nama



Dari langkah sebelumnya, saya menyadari bahwa menghapus data dalam jumlah besar menciptakan beban yang sama besarnya. Oleh karena itu, saya memutuskan untuk membuat tabel baru dari awal menggunakan sisipkan dan pindahkan data yang akan saya hapus ke dalamnya.



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


Jika Anda membuat tabel baru dengan ukuran yang sama seperti di atas, kecepatan pemrosesan juga harus menjadi 1/7 lebih cepat.



Setelah membuat tabel dan mengganti namanya, saya mulai menggunakannya sebagai tabel master. Sekarang jika saya menjatuhkan tabel dengan 300 juta rekaman, semuanya akan baik-baik saja.

Saya menemukan bahwa truncate atau drop lebih murah daripada menghapus dan memutuskan untuk menggunakan metode itu.



Performa



「Mengirimkan permintaan」



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


「...」

「...」

「uh ...?」



LANGKAH 4



Pikir ide sebelumnya akan berhasil, tetapi setelah mengirimkan permintaan penyisipan, beberapa kesalahan muncul. MySQL tidak hemat.



Saya sudah sangat lelah sehingga saya mulai berpikir bahwa saya tidak ingin melakukan ini lagi.



Saya duduk dan berpikir dan menyadari bahwa mungkin ada terlalu banyak permintaan penyisipan untuk satu waktu ...

Saya mencoba mengirim permintaan penyisipan untuk jumlah data yang harus diproses database dalam 1 hari. Terjadi!



Nah, setelah itu kami terus mengirimkan permintaan untuk jumlah data yang sama. Karena kami perlu menghapus jumlah data bulanan, kami mengulangi operasi ini sekitar 35 kali.



Mengganti nama tabel



Di sini, keberuntungan ada di pihak saya: semuanya berjalan lancar.



Lansiran hilang



Kecepatan pemrosesan batch meningkat.



Sebelumnya proses ini memakan waktu sekitar satu jam, kini membutuhkan waktu sekitar 2 menit.



Setelah saya yakin bahwa semua masalah telah terpecahkan, saya menjatuhkan 300 juta rekaman. Saya menghapus spreadsheet dan merasa terlahir kembali.



Meringkas



Saya menyadari bahwa pemrosesan rotasi diabaikan dalam pemrosesan batch dan itu adalah masalah utama. Kesalahan dalam arsitektur seperti itu hanya membuang-buang waktu.



Apakah Anda berpikir tentang beban replikasi data dengan menghapus catatan dari database? Jangan membebani MySQL.



Mereka yang fasih dalam database pasti tidak akan menghadapi masalah seperti itu. Selebihnya, semoga artikel ini bermanfaat.



Terima kasih sudah membaca!



Kami akan sangat senang jika Anda memberi tahu kami jika Anda menyukai artikel ini, apakah terjemahannya jelas, apakah bermanfaat bagi Anda?



All Articles