Kebuntuan pada transaksi dengan banyak tabel

Skenario saya umum: Saya memiliki prosedur tersimpan yang perlu memperbarui beberapa tabel. jika salah satu pembaruan gagal - semua pembaruan harus dibatalkan. jawaban yang tepat adalah dengan memasukkan semua pembaruan dalam satu transaksi dan hanya membatalkannya. namun, dalam sistem seperti milik kita, hal ini akan menyebabkan masalah konkurensi. ketika kami memecah pembaruan menjadi beberapa transaksi singkat - kami mendapatkan throughput ~30 eksekusi bersamaan per detik sebelum dan masalah kebuntuan mulai muncul. jika kita memasukkannya ke satu transaksi yang mencakup semuanya - kita mendapatkan ~2 per detik sebelum kebuntuan muncul.

dalam kasus kami, kami menempatkan blok coba-tangkap setelah setiap transaksi singkat, dan secara manual MENGHAPUS/Memperbarui kembali perubahan dari yang sebelumnya. jadi pada dasarnya kami meniru perilaku transaksi dengan cara yang sangat mahal... Ini berfungsi dengan baik karena ditulis dengan baik dan tidak mendapatkan banyak "kemunduran"... satu hal yang tidak dapat diselesaikan oleh pendekatan ini sama sekali adalah kasus batas waktu perintah dari web server / klien.

Saya telah membaca secara ekstensif di banyak formulir dan blog dan memindai melalui MSDN dan tidak dapat menemukan solusi yang baik. banyak yang telah menyampaikan masalahnya tetapi saya belum melihat solusi yang baik.

Pertanyaannya adalah ini: apakah ada solusi APA PUN untuk masalah ini yang memungkinkan pengembalian pembaruan yang stabil ke beberapa tabel, tanpa perlu membuat kunci eksklusivitas pada semua baris selama seluruh durasi transaksi panjang.

Asumsikan bahwa ini bukan masalah optimasi. Tabelnya mungkin hampir mencapai optimasi maksimal, dan dapat memberikan throughput yang sangat tinggi selama kebuntuan tidak terjadi. tidak ada kunci tabel/kunci halaman dll. semua baris terkunci pada pembaruan - tetapi ketika Anda memiliki begitu banyak sesi bersamaan, beberapa di antaranya perlu memperbarui baris yang sama...

bisa melalui SQL, sisi klien C#, sisi server C# (memperluas server SQL?). Apakah ada solusi seperti itu di buku/blog yang belum saya temukan?

kami menggunakan SQL server 2008 R2, dengan klien .NET/server web yang terhubung dengannya. Contoh kode:

Buat prosedur sptest Mulai transaksi Perbarui tabel1 Perbarui tabel2 Komit transaksi

Dalam kasus ini, jika sptest dijalankan dua kali, instance kedua tidak dapat memperbarui tabel 1 hingga instance 1 dikomit. Dibandingkan dengan ini

Buat sptest2 Perbarui tabel1 Perbarui tabel2

Sptest2 memiliki throughput yang jauh lebih tinggi - tetapi memiliki peluang untuk merusak data. Inilah yang kami coba selesaikan. Apakah ada solusi teoretis untuk hal ini?

Terima kasih, JS


person user2995891    schedule 19.03.2014    source sumber
comment
Mencoba menerapkan transaksi yang dikelola aplikasi akan gagal (saya dulu bekerja pada sistem yang mencoba). Hal yang menyenangkan tentang tingkat basis data adalah ia mampu bertahan dari hal-hal seperti pemadaman listrik mendadak dan server mogok - dapatkah Anda mengatakan hal yang sama tentang aplikasi Anda? Sistem DB telah diuji sebelumnya, sangat bagus, dan mungkin lebih cepat dibandingkan keseluruhan sistem yang dapat Anda terapkan dalam aplikasi. Bisakah kita mendapatkan rincian lebih lanjut? Mengapa Anda memiliki banyak utas yang memperbarui baris yang sama? Transaksi dimaksudkan untuk mencegah kesalahan, tapi sebaiknya hindari perselisihan terlebih dahulu...   -  person Clockwork-Muse    schedule 21.03.2014


Jawaban (2)


Menurut saya, Anda harus menggali lebih dalam untuk mengetahui alasan mengapa kebuntuan terjadi. Mungkin Anda harus mengubah urutan pembaruan untuk menghindarinya. Mungkin beberapa indeks "bersalah".

Anda tidak dapat melakukan rollback perubahan jika transaksi lain dapat mengubah data. Jadi, Anda perlu memiliki kunci pembaruan pada mereka. Namun Anda dapat menggunakan tingkat isolasi snapshot untuk memungkinkan pembacaan yang konsisten sebelum pembaruan dilakukan.

person Jānis    schedule 21.03.2014

Untuk semua tabel gabungan dalam yang sebagian besar bersifat statis atau dengan tingkat kemungkinan tinggi tidak memengaruhi kueri dengan menggunakan data kotor, maka Anda dapat menerapkan:

INNER JOIN LookupTable (with NOLOCK) lut on lut.ID=SomeOtherTableID

Ini akan memberi tahu pertanyaan bahwa saya tidak peduli dengan pembaruan yang dilakukan pada SomeOtherTable

Hal ini dapat mengurangi masalah Anda dalam banyak kasus. Untuk kebuntuan yang lebih sulit saya telah menerapkan grafik kebuntuan yang dihasilkan dan dikirim melalui email ketika kebuntuan terjadi berisi semua info rinci untuk kebuntuan tersebut.

person Ross Bush    schedule 20.03.2014
comment
Terima kasih atas jawabannya. Kami sebenarnya menggunakan with(nolock). Lebih jauh lagi, kami mencoba untuk tidak memasukkan semua pilihan dalam transaksi. Saya tahu ada solusi untuk mengelola kebuntuan, kami menggunakan beberapa, pertanyaan saya adalah solusi terprogram apa pun yang dapat menyelesaikan masalah, bukan mengelolanya. - person user2995891; 20.03.2014
comment
Apakah Anda memiliki proses yang berjalan lama dan berjalan bersamaan dengan pembaruan Anda yang mungkin menempatkan kunci eksklusif pada sumber daya Anda seperti laporan, agen layanan, pembaruan batch, dll., dll. - person Ross Bush; 20.03.2014