Untuk meringkas spesifikasinya: Kita perlu memasukkan sekitar 5 juta baris ke dalam database vendor (Oracle). Semuanya berjalan baik untuk kumpulan 500k baris menggunakan OracleBulkCopy
(ODP.NET), tetapi ketika kami mencoba untuk skala hingga 5M, kinerja mulai melambat ke perayapan setelah menyentuh tanda 1M, semakin lambat karena semakin banyak baris dimuat, dan akhirnya habis setelah 3 jam atau lebih.
Saya menduga itu terkait dengan kunci utama di atas meja, tapi aku sudah trawl forum Oracle dan Stack Overflow untuk informasi dan banyak apa yang saya baca bertentangan itu (juga, banyak posting tampaknya bertentangan satu sama lain ) . Saya berharap seseorang dapat meluruskan beberapa pertanyaan terkait erat tentang proses:
Apakah
OracleBulkCopy
kelas menggunakan pemuatan jalur konvensional atau langsung? Apakah ada cara saya dapat mengkonfirmasi ini, dengan satu atau lain cara?Dengan asumsi itu tidak digunakan langsung jalan memuat: Apakah benar bahwa Oracle secara otomatis mengatur semua indeks untuk dapat digunakan selama beban dan menempatkan mereka kembali online sesudahnya? Saya telah membaca beberapa pernyataan untuk efek ini tetapi sekali lagi, tidak dapat mengonfirmasinya.
Jika # 2 benar, maka haruskah membuat perbedaan indeks apa yang ada di meja sebelum saya memulai operasi salinan massal? Jika demikian, mengapa?
Terkait dengan # 3, apakah ada perbedaan praktis, secara umum, antara pemuatan massal dengan indeks yang tidak dapat digunakan vs benar-benar menjatuhkan indeks sebelum memuat dan membuatnya kembali sesudahnya?
Jika # 2 tidak benar, atau jika ada beberapa peringatan yang saya tidak mengerti, maka apakah ada bedanya untuk secara eksplisit membuat indeks tidak dapat digunakan sebelum memuat massal, dan kemudian secara eksplisit membangunnya kembali setelah itu?
Apakah ada hal lain, selain pembuatan indeks, yang dapat menyebabkan operasi salinan massal tumbuh semakin lambat karena semakin banyak catatan ditambahkan? (Mungkin ada hubungannya dengan logging, walaupun saya berharap operasi massal tidak dicatat?)
Jika benar-benar tidak ada cara lain untuk meningkatkan kinerja selain menjatuhkan PK / indeks terlebih dahulu, langkah-langkah apa yang dapat saya ambil untuk memastikan bahwa indeks tidak sepenuhnya hilang, yaitu jika koneksi ke database terputus di tengah proses?
Jawaban:
Beberapa hari lagi membaca dan bereksperimen dan saya dapat (kebanyakan) menjawab banyak dari ini:
Saya menemukan ini terkubur dalam dokumentasi ODP.NET (ironisnya tidak ada dalam
OracleBulkCopy
dokumen):Jadi tampak bahwa itu tidak menggunakan jalur langsung.
Ini saya dapat memverifikasi dengan melakukan operasi salinan massal besar dan mendapatkan properti indeks dari Pengembang SQL. Indeks memang muncul
UNUSABLE
saat salinan massal sedang berlangsung. Namun , saya juga menemukan bahwaOracleBulkCopy.WriteToServer
akan menolak untuk berjalan jika indeks dimulai dalamUNUSABLE
keadaan, jadi jelas ada lebih banyak yang terjadi di sini, karena jika itu sederhana seperti menonaktifkan dan membangun kembali indeks maka tidak seharusnya peduli dengan keadaan awal.Itu membuat perbedaan khusus jika indeks juga merupakan kendala . Temukan permata kecil ini di dokumentasi yang ditautkan di atas:
Dokumentasi sedikit kabur tentang apa yang terjadi selama pemuatan, terutama dengan kunci primer, tetapi satu hal yang pasti - berperilaku berbeda dengan kunci primer vs tanpa satu. Karena dengan
OracleBulkCopy
senang hati akan memungkinkan Anda melanggar batasan indeks (dan menusuk indeks ke dalamUNUSABLE
keadaan ketika selesai), firasat saya adalah bahwa itu membangun indeks PK selama salinan massal tetapi tidak memvalidasinya sampai sesudahnya.Saya tidak yakin apakah perbedaan yang diamati adalah dalam Oracle itu sendiri atau hanya kekhasan dari
OracleBulkCopy
. Juri masih keluar untuk yang satu ini.OracleBulkCopy
akan melempar pengecualian jika indeks awalnya diUNUSABLE
negara bagian, jadi itu benar-benar titik diperdebatkan.Jika ada yang faktor-faktor lain, indeks (dan indeks terutama PK) masih yang paling penting, seperti yang saya tahu oleh:
Membuat tabel sementara global dengan skema yang sama (menggunakan
CREATE AS
), kemudian menyalin massal ke tabel sementara, dan akhirnya melakukan yang lama biasaINSERT
dari tabel temp ke dalam tabel nyata. Karena tabel temp tidak memiliki indeks, salinan massal terjadi sangat cepat, dan finalINSERT
juga cepat karena data sudah ada dalam tabel (saya belum mencoba petunjuk tambahan, karena salinan table-to-table 5M baris baris sudah memakan waktu kurang dari 1 menit).Saya belum yakin tentang konsekuensi potensial dari (ab) menggunakan ruang tabel sementara dengan cara ini, tapi sejauh ini tidak memberi saya masalah, dan itu jauh lebih aman daripada alternatif dengan cara mencegah korupsi pada kedua baris atau indeks.
Keberhasilan ini juga cukup jelas menunjukkan bahwa indeks PK adalah masalahnya, karena itulah satu-satunya perbedaan praktis antara tabel temp dan tabel permanen - keduanya dimulai dengan nol baris selama pengujian kinerja.
Kesimpulan: Jangan repot-repot mencoba menyalin secara massal lebih dari sekitar 100 ribu baris ke tabel Oracle yang diindeks menggunakan ODP.NET. Baik drop indeks (jika Anda tidak benar-benar membutuhkannya) atau "preload" data ke dalam yang berbeda (non-diindeks) tabel.
sumber
Delete
tidak mungkin karena indeksnyaUNUSABLE
. Itu adalah hasil dari pengecekan kendala yang terjadi pada akhir salinan massal.alter session set skip_unusable_indexes = true;
Berikut ini adalah artikel dari Oracle yang menjelaskan kapan akan bermanfaat menggunakan insert massal atau ketika tidak. Juga, memiliki wawasan tentang apa yang terjadi di tingkat basis data.
http://docs.oracle.com/cd/B28359_01/server.111/b28319/ldr_modes.htm
sumber