TL; DR: Pertanyaan di bawah ini bermuara pada: Ketika memasukkan baris, apakah ada jendela peluang antara pembuatanIdentity
nilai baru dan penguncian kunci baris yang sesuai dalam indeks berkerumun, di mana pengamat eksternal dapat melihat yang lebih baru Identity
nilai dimasukkan oleh transaksi bersamaan? (Dalam SQL Server.)
Versi terperinci
Saya memiliki tabel SQL Server dengan Identity
kolom yang disebut CheckpointSequence
, yang merupakan kunci dari indeks berkerumun tabel (yang juga memiliki sejumlah indeks nonclustered tambahan). Baris dimasukkan ke dalam tabel oleh beberapa proses dan utas bersamaan (pada tingkat isolasi READ COMMITTED
, dan tanpa IDENTITY_INSERT
). Pada saat yang sama, ada proses membaca baris secara berkala dari indeks berkerumun, dipesan oleh CheckpointSequence
kolom itu (juga pada tingkat isolasi READ COMMITTED
, dengan READ COMMITTED SNAPSHOT
opsi dimatikan).
Saat ini saya mengandalkan fakta bahwa proses membaca tidak pernah bisa "melewati" pos pemeriksaan. Pertanyaan saya adalah: Dapatkah saya mengandalkan properti ini? Dan jika tidak, apa yang bisa saya lakukan untuk mewujudkannya?
Contoh: Ketika baris dengan nilai identitas 1, 2, 3, 4, dan 5 dimasukkan, pembaca tidak boleh melihat baris dengan nilai 5 sebelum melihat yang dengan nilai 4. Tes menunjukkan bahwa kueri, yang berisi ORDER BY CheckpointSequence
klausa ( dan WHERE CheckpointSequence > -1
klausa), andal memblokir kapan pun baris 4 dibaca, tetapi belum berkomitmen, bahkan jika baris 5 sudah dikomit.
Saya percaya bahwa setidaknya secara teori, mungkin ada kondisi ras di sini yang dapat menyebabkan asumsi ini rusak. Sayangnya, dokumentasi pada Identity
tidak mengatakan banyak tentang cara Identity
kerjanya dalam konteks beberapa transaksi bersamaan, hanya mengatakan "Setiap nilai baru dihasilkan berdasarkan pada seed & increment saat ini." dan "Setiap nilai baru untuk transaksi tertentu berbeda dari transaksi bersamaan lainnya di atas meja." ( MSDN )
Alasan saya adalah, itu harus bekerja entah bagaimana seperti ini:
- Transaksi dimulai (baik secara eksplisit atau implisit).
- Nilai identitas (X) dihasilkan.
- Kunci baris terkait diambil pada indeks berkerumun berdasarkan pada nilai identitas (kecuali jika eskalasi kunci menendang, dalam hal ini seluruh tabel terkunci).
- Baris dimasukkan.
- Transaksi dilakukan (mungkin cukup banyak waktu kemudian), sehingga kunci dihapus lagi.
Saya pikir antara langkah 2 dan 3, ada jendela yang sangat kecil di mana
- sesi bersamaan dapat menghasilkan nilai identitas berikutnya (X + 1) dan menjalankan semua langkah yang tersisa,
- sehingga memungkinkan pembaca datang tepat pada titik waktu itu untuk membaca nilai X + 1, kehilangan nilai X.
Tentu saja, kemungkinan ini tampaknya sangat rendah; tapi tetap saja - itu bisa terjadi. Atau mungkinkah itu?
(Jika Anda tertarik dengan konteksnya: Ini adalah implementasi dari SQL Persistence Engine NEventStore. NEventStore mengimplementasikan toko acara khusus-append di mana setiap acara mendapatkan nomor urut pos pemeriksaan naik yang baru. Klien membaca acara dari toko acara yang dipesan oleh pos pemeriksaan) untuk melakukan perhitungan dari segala macam. Begitu suatu peristiwa dengan pos pemeriksaan X telah diproses, klien hanya mempertimbangkan peristiwa "baru", yaitu peristiwa dengan pos pemeriksaan X +1 dan di atasnya. Oleh karena itu, sangat penting bahwa peristiwa tidak pernah dapat dilewati, karena mereka tidak akan pernah dipertimbangkan lagi. Saat ini saya mencoba untuk menentukan apakah Identity
implementasi pos pemeriksaan berbasis memenuhi persyaratan ini. Ini adalah pernyataan SQL yang tepat digunakan : Skema , permintaan Writer ,Permintaan Pembaca .)
Jika saya benar dan situasi yang dijelaskan di atas dapat muncul, saya hanya dapat melihat dua opsi untuk berurusan dengan mereka, yang keduanya tidak memuaskan:
- Saat melihat nilai urutan pos pemeriksaan X + 1 sebelum melihat X, singkirkan X + 1 dan coba lagi nanti. Namun, karena
Identity
tentu saja dapat menghasilkan kesenjangan (misalnya, ketika transaksi dibatalkan), X mungkin tidak pernah datang. - Jadi, pendekatan yang sama, tetapi menerima kesenjangan setelah n milidetik. Namun, nilai n apa yang harus saya asumsikan?
Ada ide yang lebih baik?