Terlambat, saya telah menghadapi banyak pertengkaran kunci baris. Tabel dalam pertengkaran tampaknya merupakan tabel tertentu.
Inilah yang biasanya terjadi -
- Pengembang 1 memulai transaksi dari layar ujung depan Oracle Forms
- Pengembang 2 memulai transaksi lain, dari sesi berbeda menggunakan layar yang sama
~ 5 menit, ujung depan tampaknya tidak responsif. Memeriksa sesi menunjukkan pertentangan kunci baris. "Solusi" yang dilemparkan semua orang adalah dengan mematikan sesi: /
Sebagai pengembang basis data
- Apa yang bisa dilakukan untuk menghilangkan pertikaian kunci baris?
- Apakah mungkin untuk mengetahui baris mana dari prosedur tersimpan yang menyebabkan pertikaian kunci baris ini
- Apa yang akan menjadi pedoman umum untuk mengurangi / menghindari / menghilangkan masalah seperti pengkodean itu?
Jika pertanyaan ini terasa terlalu terbuka / informasi tidak cukup, silakan mengedit / beri tahu - Saya akan melakukan yang terbaik untuk menambahkan beberapa informasi tambahan.
Tabel yang dimaksud adalah di bawah banyak sisipan dan pembaruan, saya akan mengatakan itu salah satu tabel yang paling sibuk. SP cukup kompleks - untuk menyederhanakan - mengambil data dari berbagai tabel, mengisinya ke dalam tabel kerja, banyak operasi aritmatika terjadi di meja kerja dan hasil dari tabel kerja dimasukkan / diperbarui ke dalam tabel yang dimaksud.
Versi database adalah Oracle Database 10g Edisi Enterprise Release 10.2.0.1.0 - 64bit. Alur logika dijalankan dalam urutan yang sama di kedua sesi, transaksi tidak dibuka terlalu lama (atau setidaknya saya pikir begitu), dan kunci terjadi selama eksekusi aktif transaksi.
Pembaruan: Jumlah baris tabel lebih besar dari yang saya harapkan, sekitar 3,1 juta baris. Juga, setelah menelusuri sesi saya menemukan bahwa beberapa pernyataan pembaruan untuk tabel ini tidak menggunakan indeks. Kenapa begitu - saya tidak yakin. Kolom direferensikan di mana klausa diindeks. Saat ini saya sedang membangun kembali indeks.
sumber
COMMIT
atauROLLBACK
dalam waktu yang wajar atau b) mengatur sedemikian rupa sehingga orang yang sama tidak selalu menginginkan baris yang sama pada waktu yang sama.Jawaban:
Tidak persis tetapi Anda bisa mendapatkan pernyataan SQL yang menyebabkan kunci dan pada gilirannya mengidentifikasi baris terkait dalam prosedur.
Bagian Oracle Concepts Guide on locks mengatakan, "Sebuah baris dikunci hanya ketika dimodifikasi oleh seorang penulis." Sesi lain memperbarui baris yang sama kemudian akan menunggu sesi pertama
COMMIT
atauROLLBACK
sebelum dapat melanjutkan. Untuk menghilangkan masalah Anda bisa membuat serialisasi pengguna, tetapi di sini ada beberapa hal yang dapat mengurangi masalah mungkin sampai tingkat itu tidak menjadi masalah.COMMIT
lebih sering. SetiapCOMMIT
rilis terkunci, jadi jika Anda dapat melakukan pembaruan dalam batch, kemungkinan sesi lain yang membutuhkan baris yang sama berkurang.UPDATE t1 SET f1=DECODE(f2,’a’,f1+1,f1);
harus ditulis ulang sebagai yang lebih selektif (baca kunci lebih sedikit)UPDATE t1 SET f1=f1+1 WHERE f2=’a’;
. Tentu saja jika mengubah pernyataan masih akan mengunci sebagian besar baris dalam tabel maka perubahan hanya akan memiliki manfaat keterbacaan.BULK COLLECT ... FORALL
.UPDATE
dan yangCOMMIT
. Misalnya, jika kode mengirim email setelah setiap pembaruan, pertimbangkan untuk mengantri email dan mengirimkannya setelah melakukan pembaruan.SELECT ... FOR UPDATE NOWAIT
atauWAIT 2
. Anda kemudian dapat menangkap ketidakmampuan untuk mengunci baris dan memberi tahu pengguna bahwa sesi lain memodifikasi data yang sama.sumber
Saya akan memberikan jawaban dari sudut pandang pengembang.
Menurut pendapat saya, ketika Anda menemukan pertengkaran baris seperti yang Anda jelaskan, itu karena Anda memiliki bug dalam aplikasi Anda. Dalam kebanyakan kasus, jenis pertikaian ini adalah tanda kerentanan pembaruan yang hilang. Utas ini di AskTom menjelaskan konsep pembaruan yang hilang:
Anda telah mengalami satu efek samping buruk dari pembaruan yang hilang: sesi 2 dapat diblokir karena sesi 1 belum dilakukan. Namun masalah utama adalah bahwa sesi 2 memperbarui catatan secara membabi buta. Misalkan kedua sesi mengeluarkan pernyataan:
Setelah kedua pernyataan, modifikasi session1 telah ditimpa, tanpa session2 telah diberitahu bahwa baris telah dimodifikasi oleh sesi 1.
Pembaruan yang hilang (dan efek samping pertengkaran) seharusnya tidak pernah terjadi, mereka 100% dapat dihindari. Anda harus menggunakan penguncian untuk mencegahnya dengan dua metode utama: penguncian optimis dan pesimistis .
1) Mengunci Pesimistis
Anda ingin memperbarui satu baris. Dalam mode ini Anda akan mencegah orang lain mengubah baris ini dengan meminta kunci pada baris itu (
SELECT ... FOR UPDATE NOWAIT
pernyataan). Jika baris sudah dimodifikasi, Anda akan mendapatkan pesan kesalahan, yang dapat Anda terjemahkan dengan anggun ke pengguna akhir (baris ini sedang dimodifikasi oleh pengguna lain). Jika baris tersedia, buat modifikasi Anda (PEMBARUAN), kemudian komit setiap kali transaksi Anda selesai.2) Penguncian Optimis
Anda ingin memperbarui satu baris. Namun, Anda tidak ingin mempertahankan kunci pada baris itu, mungkin karena Anda menggunakan beberapa transaksi untuk memperbarui baris (aplikasi stateless berbasis web), atau mungkin Anda tidak ingin pengguna memegang kunci terlalu lama ( yang dapat menyebabkan orang lain diblokir). Dalam hal ini Anda tidak akan langsung meminta kunci. Anda akan menggunakan penanda untuk memastikan bahwa baris tidak berubah ketika pembaruan Anda akan dikeluarkan. Anda bisa menyimpan nilai semua kolom, atau menggunakan kolom timestamp yang diperbarui secara otomatis, atau kolom berbasis urutan. Apa pun pilihan Anda, ketika Anda akan melakukan pembaruan, Anda akan memastikan bahwa penanda pada baris itu tidak berubah dengan mengeluarkan kueri seperti:
Jika kueri mengembalikan baris, buat pembaruan Anda. Jika tidak, ini berarti seseorang telah memodifikasi baris sejak terakhir kali Anda menanyakannya. Anda harus memulai kembali proses dari awal.
Catatan: Jika Anda memiliki kepercayaan penuh atas semua aplikasi yang mengakses DB Anda, Anda dapat mengandalkan pembaruan langsung untuk penguncian optimis. Anda dapat mengeluarkan langsung:
Jika pernyataan tidak memperbarui baris, Anda tahu bahwa seseorang telah mengubah baris ini dan Anda harus memulai dari awal.
Jika semua aplikasi menyetujui skema ini, Anda tidak akan pernah diblokir oleh orang lain dan Anda akan menghindari pembaruan buta. Namun, jika Anda tidak mengunci baris sebelumnya, Anda masih rentan terhadap penguncian tidak terbatas jika aplikasi lain, pekerjaan batch atau pembaruan langsung tidak menerapkan penguncian yang optimis. Inilah sebabnya saya menyarankan untuk selalu mengunci baris, apa pun pilihan skema penguncian Anda (hit kinerja dapat diabaikan karena Anda mengambil semua nilai termasuk rowid ketika Anda mengunci baris).
TL; DR
sumber
Jawaban ini mungkin memenuhi syarat untuk entri di The Daily WTF.
Benar, setelah menelusuri sesi dan mencari
USER_SOURCE
- saya melacak akar penyebabnyasumber