Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Perbaikan Bug R2 2008 yang Merusak RCSI

Salah satu perbaikan yang disertakan dalam pembaruan kumulatif 11 untuk SQL Server 2008 R2 Paket Layanan 2 mengatasi "kebuntuan yang salah" yang dapat terjadi dalam skenario tertentu (dijelaskan nanti dalam artikel ini). Sayangnya, perbaikan memperkenalkan bug baru, di mana kueri SELECT di bawah RCSI (baca isolasi snapshot yang dilakukan) mulai mengambil kunci bersama maksud tingkat tabel. Akibatnya, Anda mungkin melihat peningkatan pemblokiran (dan berpotensi menemui jalan buntu) untuk kueri RCSI setelah menerapkan 2008 R2 SP2 CU11 (atau lebih baru).

Ini akan menjadi kejutan yang tidak diinginkan bagi siapa pun yang terbiasa dengan pembaca yang tidak memblokir penulis (dan sebaliknya) saat menggunakan RCSI. Tidak ada perbaikan untuk bug RCSI pada saat penulisan. Faktanya, item Connect yang dibuat oleh Eugene Karpovich untuk melaporkan masalah tersebut telah ditutup sebagai "Tidak Akan Diperbaiki", meskipun saya memahami bahwa keputusan ini sedang ditinjau.

Biasanya, masalah ini mungkin tidak menjadi masalah besar, karena pembaruan kumulatif umumnya tidak diterapkan secara luas seperti paket layanan lengkap. Namun, Microsoft baru-baru ini mengumumkan akan ada Final Service Pack 3 untuk SQL Server 2008 R2. Paket layanan ini akan menjadi roll up sederhana dari pembaruan kumulatif SP2 yang ada (hingga dan termasuk CU13) tetapi tanpa perbaikan baru. Hasil dari semua ini adalah, kecuali ada perubahan sementara itu, pengguna yang menerapkan SP3 akan tiba-tiba mulai terpengaruh oleh bug RCSI yang diperkenalkan di CU11.

edit:Tepat sebelum artikel ini diterbitkan, Microsoft mengkonfirmasi regresi ini akan diperbaiki di SP3.

Bug "kebuntuan yang salah" yang sama (yang perbaikannya memperkenalkan bug baru) juga diperbaiki di Pembaruan Kumulatif 8 untuk SQL Server 2012 Paket Layanan 1 seperti yang dijelaskan dalam KB2923460. Perbaikan untuk SQL Server 2012 berbeda, dan tidak memperkenalkan masalah RCSI baru.

SQL Server 2014 tidak pernah terpengaruh oleh kedua masalah tersebut, sejauh yang saya tahu. Tentu saja tidak ada dokumentasi untuk menunjukkan sebaliknya, dan pengujian yang saya lakukan pada RTM 2014, CU1, dan CU2 tidak mereproduksi salah satu pun dari bug.

Bug RCSI R2 2008

Kueri SELECT yang berjalan di bawah RCSI biasanya hanya membutuhkan kunci stabilitas skema (Sch-S), yang kompatibel dengan semua kunci lain kecuali kunci modifikasi skema (Sch-M). Ketika CU11 (atau yang lebih baru) diterapkan ke contoh SQL Server 2008 R2, kueri ini mulai mengambil kunci tingkat tabel bersama maksud (Tab-IS). Skrip pengujian berikut dapat digunakan untuk menunjukkan perbedaan perilaku:

GUNAKAN master;GOSET TRANSACTION ISOLATION LEVEL READ COMMITTED;SET NOCOUNT ON;GOCREATE DATABASE RCSI;GOALTER DATABASE RCSISET READ_COMMITTED_SNAPSHOT ON;GOALTER DATABASE RCSISET ALLOW_SNAPSHOT_ISOLATION OFF;GOCRE ID integer NOT NULL, CONSTRAINT PK_Test PRIMARY KEY CLUSTERED (id));GOINSERT dbo.Test (col1) NILAI (1), (2), (3), (4);GO-- Show locksDBCC TRACEON (1200, 3604, -1 ) DENGAN NO_INFOMSGS;SELECT * FROM dbo.Test;DBCC TRACEOFF (1200, 3604, -1) DENGAN NO_INFOMSGS;GOALTER DATABASE RCSISET SINGLE_USERWITH ROLLBACK SEGERA; GUNAKAN induk; DROP DATABASE RCSI;

Saat dijalankan terhadap instance SQL Server 2008 R2 tanpa bug, output debug menunjukkan satu kunci Sch-S yang diambil untuk pernyataan pengujian seperti yang diharapkan:

Proses memperoleh kunci Sch-S pada OBJECT:7:2105058535:0 hasil:OK
Proses melepaskan kunci pada OBJECT:7:2105058535:0

Saat dijalankan terhadap SQL Server 2008 R2 build 10.50.4302 (atau lebih tinggi) outputnya mirip dengan:

Proses memperoleh kunci IS pada OBJECT:7:2105058535:0 hasil:OK
Proses melepaskan kunci pada OBJECT:7:2105058535:0

Perhatikan bahwa kunci Sch-S telah diganti dengan kunci Tab-IS.

Implikasi dan Mitigasi

Kunci yang dibagikan dengan maksud (IS) masih merupakan kunci yang sangat kompatibel, tetapi tidak begitu ramah konkurensi seperti Sch-S. Matriks kompatibilitas kunci menunjukkan bahwa kunci IS bertentangan dengan:

  • Sch-M (modifikasi skema) – sesuai Sch-S
  • BU (pembaruan massal)
  • X (eksklusif)

Ketidakcocokan dengan kunci eksklusif (X) berarti pembacaan di bawah RCSI akan memblokir jika proses bersamaan memegang kunci eksklusif pada sumber daya yang sama. Demikian juga, penulis yang membutuhkan kunci eksklusif akan memblokir jika pembaca RCSI bersamaan memegang kunci IS. Kunci ekslusif diperoleh setiap kali data diubah, dan ditahan hingga akhir transaksi, sehingga efek dari bug adalah bahwa pembaca di bawah RCSI akan diblokir oleh penulis bersamaan (dan sebaliknya) ketika tidak sebelum CU11 diterapkan.

Faktor mitigasi yang signifikan adalah bahwa bug hanya menyebabkan tingkat tabel kunci bersama maksud untuk diambil. Penulis bersamaan yang membutuhkan level tabel kunci eksklusif akan menyebabkan pemblokiran (dan berpotensi kebuntuan). Namun, penulis bersamaan yang hanya memerlukan kunci eksklusif pada tingkat yang lebih rendah (mis. baris, halaman, atau partisi) tidak menyebabkan pemblokiran atau kebuntuan. Pada tingkat tabel, penulis ini hanya akan memperoleh kunci intent-eksklusif (IX), yang kompatibel dengan Tab-IS. Kunci eksklusif yang diambil pada tingkat perincian yang lebih rendah tidak akan menyebabkan konflik.

Di sebagian besar sistem, kunci eksklusif tingkat tabel (Tab-X) akan relatif jarang. Kecuali diminta secara eksplisit menggunakan petunjuk TABLOCKX, beberapa kemungkinan penyebab kunci Tab-X adalah:

  • Kunci eskalasi dari perincian yang lebih rendah
  • Menggunakan SERIALIZABLE tanpa indeks pendukung untuk kunci rentang kunci

Solusi teknis adalah dengan menambahkan petunjuk tabel (berlebihan) WITH (READCOMMITTED) ke setiap tabel di setiap kueri yang berjalan di bawah RCSI. Ini terjadi untuk melewati bug sehingga hanya kunci Sch-S yang diambil, tetapi ini bukanlah proposisi yang praktis.

Terlepas dari mitigasi ini, menggunakan Tab-IS untuk kueri hanya baca di bawah RCSI masih merupakan perilaku yang salah. Saya harap ini dapat diperbaiki untuk SQL Server 2008 R2 sebelum Service Pack 3 dirilis.

Bug "Kebuntuan Salah"

Seperti disebutkan sebelumnya, bug RCSI diperkenalkan sebagai efek samping dari perbaikan bug "kebuntuan yang salah". Masalah sebelumnya ini didokumentasikan untuk SQL Server 2008 R2 di KB2929464 dan untuk SQL Server 2012 di KB2923460. Tidak ada dokumen yang merupakan model kejelasan (atau akurasi), tetapi masalah mendasarnya cukup menarik, jadi saya ingin meluangkan sedikit waktu untuk melihatnya di sini.

Pada dasarnya, kebuntuan terjadi ketika:

  • Tiga atau lebih transaksi bersamaan dibaca dari tabel yang sama
  • Petunjuk UPDLOCK dan TABLOCK digunakan dalam ketiga kasus
  • Pengaturan basis data READ_COMMITTED_SNAPSHOT AKTIF

Perhatikan bahwa tidak masalah tingkat isolasi mana yang menjalankan transaksi. Untuk mereproduksi bug, pertama jalankan skrip penyiapan di bawah ini:

(Pra>GUNAKAN master;GOSET TRANSACTION ISOLATION LEVEL READ COMMITTED;GOCREATE DATABASE IncorrectDeadlock;GOALTER DATABASE IncorrectDeadlock SET READ_COMMITTED_SNAPSHOT ON;GOUSE IncorrectDeadlock;GOCREATE TABLE dbo.Test( id integer IDENTITAS BUKAN NULL, CETAK integer NULL, CETAK NULL, CETAK NULL id));GOINSERT dbo.Test (col1) NILAI (1);

Selanjutnya, jalankan skrip berikut dalam tiga koneksi terpisah (perhatikan bahwa transaksi dibiarkan terbuka):

GUNAKAN IncorrectDeadlock;GOSET TRANSACTION ISOLATION LEVEL READ COMMITTED;GOBEGIN TRANSACTION;SELECT T.id, T.col1FROM dbo.Test AS T WITH (UPDLOCK, TABLOCK);

Pada titik ini, sesi pertama akan mengembalikan kumpulan hasil dan dua lainnya akan diblokir. "Kebuntuan yang salah" muncul ketika sesi pertama menyelesaikan transaksinya (baik melakukan atau memutar kembali). Ketika ini terjadi, salah satu dari dua sesi lainnya akan melaporkan kebuntuan:

Kebuntuan terjadi karena dua sesi yang sebelumnya diblokir menahan Tab-IX (eksklusif maksud tingkat tabel) dan keduanya ingin mengonversi kuncinya menjadi Tab-X (eksklusif tingkat tabel). Tab-IX kompatibel dengan Tab-IX lain, tetapi tidak dengan Tab-X. Ini adalah kebuntuan konversi (dan ironisnya di sini UPDLOCK sering digunakan untuk menghindari kebuntuan konversi).

Jangan ragu untuk memvariasikan tingkat isolasi transaksi untuk tiga kueri sesuai keinginan. Kebuntuan akan tetap terjadi, selama RCSI diaktifkan, dengan kunci yang sama terlibat. Setelah pengujian selesai, hapus database pengujian:

GUNAKAN IncorrectDeadlock; ALTER DATABASE IncorrectDeadlockSET SINGLE_USER DENGAN ROLLBACK SEGERA; GUNAKAN induk; DROP DATABASE IncorrectDeadlock;

Analisis dan Penjelasan

Saya pribadi tidak ingat pernah menggunakan UPDLOCK dan TABLOCK bersama-sama dalam kode saya. Bagi saya, kombinasi petunjuk ini tampaknya aneh secara intuitif karena SQL Server tidak memiliki kunci pembaruan tingkat tabel . Jadi, apa artinya artinya untuk menentukan petunjuk UPDLOCK dan TABLOCK secara bersamaan?

Dokumentasi mengatakan ini:

UPDLOCK

Menentukan bahwa kunci pembaruan harus diambil dan ditahan hingga transaksi selesai. UPDLOCK mengambil kunci pembaruan untuk operasi baca hanya di tingkat baris atau tingkat halaman. Jika UPDLOCK digabungkan dengan TABLOCK, atau kunci level tabel diambil karena alasan lain, kunci eksklusif (X) akan diambil sebagai gantinya.

Ini menunjukkan bahwa kombinasi petunjuk harus menghasilkan satu kunci meja eksklusif. Sebenarnya, ini bukan keseluruhan cerita:

Di SQL Server 2000, menggabungkan petunjuk UPDLOCK dan TABLOCK menghasilkan Tab-S (kunci tabel bersama) yang diambil diikuti oleh konversi ke Tab-X (kunci tabel eksklusif) di bawah semua tingkat isolasi kecuali READ UNCOMMITTED. Urutan penguncian ini dapat mengakibatkan kebuntuan di mana tiga atau lebih sesi terlibat:dua sesi memperoleh Tab-S dan keduanya menunggu di sisi lain untuk mengonversi ke Tab-X. Di bawah READ UNCOMMITTED, SQL Server 2000 mengambil Sch-S kemudian Tab-X, yang tidak rentan terhadap kebuntuan (hanya pemblokiran normal).

Di SQL Server 2005 dan seterusnya (tanpa perbaikan bug) kunci yang diambil hanya tentang apakah RCSI diaktifkan atau tidak. Jika RCSI diaktifkan, semua tingkat isolasi ambil Tab-IX lalu konversikan ke Tab-X. Urutan ini menyebabkan kebuntuan alamat perbaikan bug.

Jika RCSI tidak diaktifkan, tingkat isolasi yang cocok berperilaku seperti yang mereka lakukan di bawah SQL Server 2000 (mengambil Tab-S kemudian mengonversi ke Tab-X). Tingkat isolasi snapshot (baru untuk 2005) mengambil Sch-S diikuti oleh Tab-X. Akibatnya, SI dan READ UNCOMMITTED adalah satu-satunya level isolasi yang tidak rentan terhadap kebuntuan ini dalam skenario UPDLOCK, TABLOCK saat RCSI tidak diaktifkan.

Perbaikan Kebuntuan

Perbaikan mengubah kunci yang diambil saat UPDLOCK dan TABLOCK ditentukan bersama, untuk semua tingkat isolasi , dan apapun apakah RCSI diaktifkan atau tidak. Setelah perbaikan diterapkan, UPDLOCK dan TABLOCK menyebabkan mesin memperoleh Tab-SIX (tingkat tabel yang dibagikan dengan maksud eksklusif), yang kemudian dikonversi ke Tab-X.

Ini menghindari skenario kebuntuan karena Tab-SIX tidak kompatibel dengan Tab-SIX lain. Ingat, kebuntuan terjadi ketika dua proses menahan Tab-IX menunggu untuk dikonversi ke Tab-X. Dengan Tab-IX digantikan oleh Tab-SIX, tidak mungkin keduanya menahan Tab-SIX pada saat yang bersamaan. Hasilnya adalah skenario pemblokiran normal alih-alih kebuntuan.

Pemikiran Terakhir

Perbaikan "kebuntuan yang salah" memang menyelesaikan satu skenario kebuntuan tertentu, tetapi itu masih tidak menghasilkan perilaku yang saya bayangkan oleh orang-orang yang menentukan UPDLOCK dan TABLOCK yang dibayangkan. Jika SQL Server memang memiliki kunci Tab-U (pembaruan tingkat tabel), itu akan mencegah perubahan bersamaan pada tabel tetapi memungkinkan pembaca bersamaan. Inilah yang saya bayangkan maksud dari orang-orang yang menggunakan petunjuk ini bersama-sama, dan saya dapat melihat bagaimana itu mungkin berguna.

Implementasi saat ini (di mana Tab-X pada akhirnya diambil alih-alih Tab-U yang hilang) tidak sesuai dengan harapan ini karena Tab-X mencegah pembacaan bersamaan (kecuali jika tingkat isolasi versi baris digunakan). Kami mungkin juga menentukan TABLOCKX dalam banyak kasus. Fakta bahwa perbaikan tersebut juga memperkenalkan bug baru (hanya untuk pengguna SQL Server 2008 R2) juga disayangkan, terutama jika bug tersebut terus disertakan dalam 2008 R2 SP3.

Perhatikan bahwa perbaikan kebuntuan tidak tersedia untuk versi SQL Server sebelum 2008 R2. Versi ini akan terus memiliki perilaku penguncian yang kompleks untuk UPDLOCK dan TABLOCK seperti yang dijelaskan di atas.

Terima kasih saya kepada Eugene Karpovich yang pertama kali membawa masalah ini menjadi perhatian saya dalam komentar di artikel saya tentang Modifikasi Data Di Bawah RCSI.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Memahami Jenis dan Format MapReduce

  2. Perbedaan Antara Pernyataan JDBC dan Pernyataan yang Disiapkan

  3. Cara menghapus kolom dalam tabel

  4. Lebih lanjut tentang CXPACKET Menunggu:Paralelisme Miring

  5. Mengonfigurasi Izin ScaleGrid di AWS Menggunakan Template Kebijakan IAM