Saya mengelola aplikasi yang sangat besar (hampir 1TB data dengan lebih dari 500 juta baris dalam satu tabel) database Oracle back end. Basis data tidak benar-benar melakukan apa-apa (tidak ada SProcs, tidak ada pemicu atau apa pun) itu hanya menyimpan data.
Setiap bulan kita diharuskan untuk membersihkan catatan dari dua tabel utama. Kriteria untuk pembersihan bervariasi dan merupakan kombinasi umur baris dan beberapa bidang status. Kami biasanya membersihkan antara 10 dan 50 juta baris per bulan (kami menambahkan sekitar 3-5 juta baris per minggu melalui impor).
Saat ini kami harus melakukan penghapusan ini dalam batch sekitar 50.000 baris (mis. Hapus 50000, komit, hapus 50000, komit, ulangi). Mencoba menghapus seluruh kumpulan sekaligus, membuat basis data tidak responsif selama sekitar satu jam (tergantung pada # baris). Menghapus baris dalam batch seperti ini sangat kasar pada sistem dan kami biasanya harus melakukannya "sesuai waktu" selama satu minggu; membiarkan skrip berjalan terus menerus dapat mengakibatkan penurunan kinerja yang tidak dapat diterima pengguna.
Saya percaya bahwa penghapusan batch seperti ini juga menurunkan kinerja indeks dan memiliki dampak lain yang akhirnya menyebabkan kinerja database menurun. Ada 34 indeks hanya dalam satu tabel, dan ukuran data indeks sebenarnya lebih besar dari data itu sendiri.
Berikut ini skrip yang digunakan oleh salah satu staf TI kami untuk melakukan pembersihan ini:
BEGIN
LOOP
delete FROM tbl_raw
where dist_event_date < to_date('[date]','mm/dd/yyyy') and rownum < 50000;
exit when SQL%rowcount < 49999;
commit;
END LOOP;
commit;
END;
Basis data ini harus mencapai 99,99999% dan kami hanya memiliki jendela pemeliharaan 2 hari setahun sekali.
Saya mencari metode yang lebih baik untuk menghapus catatan ini, tetapi saya belum menemukan. Ada saran?
sumber
Jawaban:
Logika dengan 'A' dan 'B' mungkin "disembunyikan" di belakang kolom virtual tempat Anda dapat melakukan partisi:
sumber
Solusi klasik untuk ini adalah untuk mempartisi tabel Anda, misalnya berdasarkan bulan atau minggu. Jika Anda belum pernah melihatnya, tabel partisi seperti beberapa tabel terstruktur identik dengan implisit
UNION
saat memilih, dan Oracle akan secara otomatis menyimpan baris di partisi yang sesuai saat memasukkannya berdasarkan kriteria partisi. Anda menyebutkan indeks - baik setiap partisi mendapatkan indeks dipartisi sendiri juga. Ini adalah operasi yang sangat murah di Oracle untuk menjatuhkan partisi (analog dengan aTRUNCATE
dalam hal memuat karena itulah yang benar-benar Anda lakukan - memotong atau menjatuhkan salah satu dari sub-tabel yang tidak terlihat ini). Ini akan menjadi jumlah yang signifikan dari pemrosesan untuk dipartisi "setelah fakta", tetapi tidak ada gunanya menangisi susu yang tumpah - keuntungan untuk melakukannya sejauh ini lebih besar daripada biayanya. Setiap bulan Anda akan membagi partisi atas untuk membuat partisi baru untuk data bulan berikutnya (Anda dapat dengan mudah mengotomatisasikannya dengan aDBMS_JOB
).Dan dengan partisi Anda juga dapat mengeksploitasi kueri paralel dan penghapusan partisi , yang seharusnya membuat pengguna Anda sangat senang ...
sumber
A
maka jikaDateA
lebih dari 3 tahun, maka akan dihapus. Jika Status adalahB
danDateB
lebih tua dari 10 tahun, hal itu akan dibersihkan. Jika pemahaman saya tentang partisi benar, maka partisi tidak akan berguna dalam situasi seperti ini (setidaknya sejauh menyangkut pembersihan).Satu aspek yang perlu dipertimbangkan adalah berapa banyak hasil kinerja penghapusan dari indeks dan berapa banyak dari tabel mentah. Setiap catatan yang dihapus dari tabel membutuhkan penghapusan baris yang sama dari setiap indeks btree. Jika Anda memiliki indeks 30+ btree, saya menduga sebagian besar waktu Anda dihabiskan untuk pemeliharaan indeks.
Ini berdampak pada kegunaan partisi. Katakanlah Anda memiliki indeks atas nama. Indeks Btree standar, semua dalam satu segmen, mungkin harus melakukan empat lompatan untuk mendapatkan dari blok root ke blok daun dan yang kelima membaca untuk mendapatkan baris. Jika indeks itu dipartisi menjadi 50 segmen dan Anda tidak memiliki kunci partisi sebagai bagian dari kueri, maka masing-masing dari 50 segmen tersebut perlu diperiksa. Setiap segmen akan lebih kecil, jadi Anda mungkin hanya harus melakukan 2 lompatan tetapi Anda mungkin masih akan selesai membaca 100 kali daripada yang sebelumnya 5.
Jika mereka adalah indeks bitmap, persamaannya berbeda. Anda mungkin tidak menggunakan indeks untuk mengidentifikasi baris individual, melainkan mengaturnya. Jadi, alih-alih permintaan menggunakan 5 IO untuk mengembalikan satu catatan, itu menggunakan 10.000 IO. Karenanya overhead tambahan di partisi ekstra untuk indeks tidak akan menjadi masalah.
sumber
penghapusan 50 juta catatan per bulan dalam batch 50.000 hanya 1000 iterasi. jika Anda melakukan 1 hapus setiap 30 menit itu harus memenuhi kebutuhan Anda. tugas terjadwal untuk menjalankan kueri yang Anda poskan tetapi menghapus loop sehingga hanya dijalankan sekali seharusnya tidak menyebabkan penurunan yang nyata bagi pengguna. Kami melakukan volume rekaman yang sama di pabrik kami yang beroperasi hampir 24/7 dan memenuhi kebutuhan kami. Kami benar-benar menyebarkan 10.000 catatan lebih sedikit setiap 10 menit, yang dijalankan dalam sekitar 1 atau 2 detik berjalan pada server Oracle unix kami.
sumber
Jika ruang disk tidak pada premium, Anda bisa dapat membuat "tabel" salinan tabel, katakanlah
my_table_new
, menggunakan CTAS (Buat Tabel Sebagai Pilih) dengan kriteria yang akan menghilangkan catatan yang akan dihapus. Anda dapat melakukan pernyataan buat secara paralel, dan dengan petunjuk tambahkan untuk membuatnya cepat, lalu buat semua indeks Anda. Kemudian, setelah selesai, (dan diuji), ubah nama tabel yang ada menjadimy_table_old
dan ubah nama tabel "work" menjadimy_table
. Setelah Anda merasa nyaman dengan semuanyadrop my_table_old purge
untuk menyingkirkan meja lama. Jika ada banyak batasan kunci asing, lihatdbms_redefinition
paket PL / SQL . Ini akan mengkloning indeks Anda, kendala, dll. Saat menggunakan opsi yang sesuai. Ini adalah ringkasan dari saran Tom Kyte dari AskTomketenaran. Setelah menjalankan pertama, Anda dapat mengotomatiskan semuanya, dan tabel buat harus berjalan lebih cepat, dan dapat dilakukan saat sistem dinyalakan, dan waktu henti aplikasi akan dibatasi hingga kurang dari satu menit untuk melakukan penggantian nama tabel. Menggunakan CTAS akan jauh lebih cepat daripada melakukan beberapa penghapusan batch. Pendekatan ini bisa sangat berguna jika Anda tidak memiliki partisi berlisensi.Sampel CTAS, menjaga baris dengan data dari 365 hari terakhir dan
flag_inactive = 'N'
:sumber
ketika menjatuhkan partisi, Anda meninggalkan indeks global tidak dapat digunakan, yang perlu dibangun kembali, pembangunan kembali indeks global akan menjadi masalah besar, karena jika Anda melakukannya secara online, itu akan sangat lambat, jika tidak, Anda perlu downtime. dalam kedua kasus, tidak dapat memenuhi persyaratan.
"Kami biasanya membersihkan antara 10 dan 50 juta baris per bulan"
Saya akan merekomendasikan menggunakan PL / SQL batch delete, beberapa jam ok saya pikir.
sumber