Hapus Massal untuk Tabel Besar di MySQL

9

Saya memiliki tabel Notifikasi berisi sekitar 100 juta baris host di Amazon RDS dengan 1000 IOPS, dan saya ingin menghapus baris yang lebih lama dari satu bulan.

Jika saya melakukannya DELETE FROM NOTIFICATION WHERE CreatedAt < DATE_SUB(CURDATE(), INTERVAL 30 day);, semua IOPS akan diambil, prosesnya akan memakan waktu berjam-jam, dan banyak entri baru tidak dapat dimasukkan karena "Kunci waktu tunggu tunggu terlampaui; coba mulai ulang transaksi".

Saya mencoba melakukan cara yang dijelaskan di sini: http://mysql.rjweb.org/doc.php/deletebig Namun, saya menggunakan UUID sebagai ganti increment ID.

Apa cara yang benar dan efisien untuk menghapus baris-baris itu tanpa memengaruhi data baru yang disisipkan / perbarui?

Tianyi Cong
sumber
Anda benar ypercube, saya telah memperbaikinya. Terima kasih telah menunjukkan!
Tianyi Cong
Menghapus catatan dalam bongkahan yang lebih kecil, tidak memengaruhi operasi sisipan, saya mencobanya dengan lingkaran, dan selesai menghapus 70 juta catatan dalam waktu kurang dari satu jam rathishkumar.in/2017/12/…
Rathish

Jawaban:

11

Buat tabel temp, ganti masuk dan keluar, dan salin data 30 hari terakhir ke dalamnya.

#
# Make empty temp table
#
CREATE TABLE NOTIFICATION_NEW LIKE NOTIFICATION;
#
# Switch in new empty temp table
#
RENAME TABLE NOTIFICATION TO NOTIFICATION_OLD,NOTIFICATION_NEW TO NOTIFICATION;
#
# Retrieve last 30 days data 
#
INSERT INTO NOTIFICATION SELECT * FROM NOTIFICATION_OLD
WHERE CreatedAt >= DATE_SUB(CURDATE(), INTERVAL 30 DAY);

Di jam-jam libur Anda, jatuhkan meja lama

DROP TABLE NOTIFICATION_OLD;

Inilah Keuntungan melakukan DELETE seperti ini

  1. NOTIFICATION dikosongkan dengan cepat dengan cara beralih di meja kosong.
  2. NOTIFICATION segera tersedia untuk INSERT baru
  3. 30 hari yang tersisa ditambahkan kembali ke NOTIFICATIONsaat INSERT baru dapat berlangsung.
  4. Menjatuhkan versi lama NOTIFICATIONtidak mengganggu INSERT baru
  5. CATATAN: Saya telah merekomendasikan melakukan umpan-dan-beralih untuk DELETE meja sebelum: (Lihat posting 19 Juli 2012 saya: Mengoptimalkan Permintaan DELETE di Tabel MEMORY MySQL )

Cobalah !!!

RolandoMySQLDBA
sumber
Terima kasih, Rolando! Bagaimana MySql menangani drop table secara internal? Pertama-tama hapus semua kolom lalu hapus tabel atau yang lainnya? Apakah akan membutuhkan waktu yang jauh lebih singkat daripada menghapus kolom-kolom itu?
Tianyi Cong
Saya menerapkan strategi ini pada pementasan, apakah perintah rename harus dimulai dengan "RENAME TABLE"?
Tianyi Cong
apakah akan ada perbedaan jika saya menggunakannya di dalam blok transaksi, mengingat waktu tunggu tunggu kunci, juga akan ada kontra jika meja saya yang sebenarnya sangat besar yang sekarang diganti nama dan harus dijatuhkan
Muhammad Omer Aslam
1
@MuhammadOmerAslam dalam kasus itu, file ibdata1 (tablespace sistem) hanya akan tumbuh di batalkan log. Ini khususnya kasus ketika ibdata1 akan mulai semakin besar dalam filesize (Lihat posting lama saya dba.stackexchange.com/questions/40730/… ). Anda perlu lebih berhati-hati dengan menggunakan pt-archiver seperti yang disebutkan dalam jawaban akuzminsky, Ini dapat diperlambat untuk menghapus baris dalam potongan dan kemudian menggunakan pt-online-skema-perubahan untuk menjalankan ALTER TABLE ENGINE=InnoDB untuk mengecilkan tabel.
RolandoMySQLDBA
1
@MuhammadOmerAslam Pendekatan di atas akan sempurna ketika Anda menjadwalkan waktu henti. Mengikuti tautan dalam jawaban akuzminsky ( percona.com/doc/percona-toolkit/LATEST/pt-archiver.html ). Anda dapat menggunakan pt-archiver untuk mengarsipkan data atau hanya menghapus data tanpa pengarsipan.
RolandoMySQLDBA
3

Favorit saya adalah pengarsip-pt dari Percona Toolkit. Ini mengurus beban MySQL, replikasi lag.

akuzminsky
sumber
Terima kasih, akuzminsky! Saya akan memeriksanya. Saya biasa mencoba Percona ketika saya ingin mengubah tabel notifikasi ini dengan pt-online-schema-change. Namun, diperlukan hak SUPER untuk melakukan perubahan, yang tidak disediakan oleh RDS. BTW apakah Anda tahu cara yang baik untuk mengubah meja besar?
Tianyi Cong
@TianyiCong Anda memiliki pertanyaan baru: silakan tanyakan sebagai pertanyaan baru dan mungkin komentar di sini dengan tautan, jangan tanyakan dalam komentar yang bukan cara kerja situs ini.
Jack bilang coba topanswers.xyz
-2

buat tabel notification_temp sebagai pilih * dari notifikasi tempat CreatedAt <DATE_SUB (CURDATE (), INTERVAL 30 hari);

pemberitahuan drop table;

RENAME notification_temp TO NOTIFICATION;

pengguna52557
sumber
Dan ini tidak akan memengaruhi data baru yang dimasukkan / diperbarui? Saya kira tidak.
Colin 't Hart
Metode ini memiliki 2 masalah 1) membuat NOTIFIKASI tidak tersedia selama DROP TABLE. 2) MASUKKAN yang terjadi selama CREATE TABLEterjawab.
RolandoMySQLDBA
Masalah lain: seharusnya mengatakanRENAME TABLE notification_temp ...
RolandoMySQLDBA