Saya tahu saya membangkitkan pertanyaan yang cukup lama, tetapi saya baru-baru ini mengalami masalah ini, tetapi membutuhkan sesuatu yang berskala besar dengan baik . Tidak ada data kinerja yang ada, dan karena pertanyaan ini mendapat sedikit perhatian, saya pikir saya akan memposting apa yang saya temukan.
Solusi yang benar-benar berhasil adalah sub-query /NOT IN
metode ganda Alex Barrett (mirip dengan Bill Karwin ), dan metode QuassnoiLEFT JOIN
.
Sayangnya, kedua metode di atas membuat tabel sementara menengah yang sangat besar dan kinerja menurun dengan cepat karena jumlah record yang tidak dihapus menjadi besar.
Apa yang saya putuskan menggunakan sub-kueri ganda Alex Barrett (terima kasih!) Tetapi menggunakan <=
alih-alih NOT IN
:
DELETE FROM `test_sandbox`
WHERE id <= (
SELECT id
FROM (
SELECT id
FROM `test_sandbox`
ORDER BY id DESC
LIMIT 1 OFFSET 42
) foo
)
Ini digunakan OFFSET
untuk mendapatkan id dari record N dan menghapus record itu dan semua record sebelumnya.
Karena pengurutan sudah merupakan asumsi dari masalah ini ( ORDER BY id DESC
), <=
sangat cocok.
Ini jauh lebih cepat, karena tabel sementara yang dibuat oleh subkueri hanya berisi satu catatan, bukan catatan N.
Kasus cobaan
Saya menguji tiga metode kerja dan metode baru di atas dalam dua kasus pengujian.
Kedua kasus pengujian menggunakan 10.000 baris yang ada, sedangkan pengujian pertama menyimpan 9000 (menghapus 1000 terlama) dan pengujian kedua menyimpan 50 (menghapus 9950 terlama).
+
| | 10000 TOTAL, KEEP 9000 | 10000 TOTAL, KEEP 50 |
+
| NOT IN | 3.2542 seconds | 0.1629 seconds |
| NOT IN v2 | 4.5863 seconds | 0.1650 seconds |
| <=,OFFSET | 0.0204 seconds | 0.1076 seconds |
+
Yang menarik adalah bahwa <=
metode ini melihat kinerja yang lebih baik secara keseluruhan, tetapi sebenarnya semakin baik semakin banyak Anda simpan, bukan semakin buruk.