MSSQL Server’da LCK_M_RS_S ve LCK_M_RIn_NL Lock Türleri

SQL Server dünyasında bu kilit türleri genellikle Key-Range Locking (Anahtar Aralığı Kilitleme) mekanizmasıyla ilgilidir. Özellikle Serializable izolasyon seviyesinde, “Phantom Read” (Hayalet Okuma) durumunu engellemek için kullanılırlar.

Bu kısaltmaların ne anlama geldiğini ve neden ortaya çıktıklarını adım adım inceleyelim.

1. LCK_M_RS_S (Range-Shared Share)

Bu kilit türü, bir veri aralığının hem okunduğunu hem de bu aralığa yeni verilerin eklenmesinin engellendiğini gösterir.

  • RS (Range-Shared): Belirli bir anahtar aralığının (örneğin ID’si 10 ile 20 arasındakiler) koruma altına alındığını ifade eder. Serializable izolasyon seviyesinde tamamını almaktadır.
  • S (Share): Mevcut kaydın kendisi üzerinde paylaşımlı (Shared) kilit olduğunu belirtir.

Bir sorgu WHERE ID BETWEEN 10 AND 20 dediğinde ve izolasyon seviyesi SERIALIZABLE olduğunda, SQL Server hem mevcut kayıtları kilitler hem de bu aralığa (örneğin 15 değerine sahip) yeni bir satır eklenmesini yasaklar.

2. LCK_M_RIn_NL (Range-Insert Null)

Bu kilit türü genellikle bir intent kilididir. Bir aralığa yeni bir satır eklenmeden önce, o aralığın uygun olup olmadığını kontrol etmek için kullanılır.

  • RIn (Range-Insert): Bir aralığa veri ekleneceğini (Insert) belirtir.
  • NL (Null): Mevcut bir kayıt üzerinde doğrudan bir kilit olmadığını, sadece aralıkla ilgilenildiğini gösterir.

Yeni bir satır eklemek istediğinizde, SQL Server ekleme yapacağınız boşluğu (slot) rezerve etmek için bu kilidi kullanır. Eğer başka bir işlem o aralığı RS_S ile kilitlemişse, RIn_NL kilidi beklemeye geçer.

Karşılaştırma Tablosu

Kilit TürüAçılımıAmacıGenelde Ne Zaman Görülür?
RS_SRange-Shared ShareAralıktaki veriyi korumak ve yeni veri ekletmemek.SELECT sorgularında (Serializable seviyesinde).
RIn_NLRange-Insert NullAralıktaki bir boşluğa yeni veri eklemek.INSERT işlemlerinde (Serializable seviyesinde).

Eğer sisteminizde bu kilitler yüzünden Blocking (engellenme) yaşanıyorsa, genellikle şu durumlar söz konusudur:

  1. Serializable İzolasyon Seviyesi: Uygulamanız veya bir kütüphane (Entity Framework vb.) farkında olmadan bu seviyeyi kullanıyor olabilir. Bu seviye en katı seviyedir ve performansı düşürebilir.
  2. Eksik İndeksler: SQL Server bir aralığı kilitlemek istediğinde uygun bir indeks bulamazsa, tüm tabloyu kilitlemek zorunda kalabilir. Bu da devasa performans kayıplarına yol açar.

Eğer bu kilitlerle çok sık karşılaşıyorsanız, sorgularınızda WITH (NOLOCK) kullanmak yerine (çünkü bu kirli okumaya sebep olur), izolasyon seviyesini Read Committed Snapshot Isolation (RCSI) olarak değiştirmeyi düşünebilirsiniz.

Exclusive (X) ve Shared (S) uyumsuz olduğu için, İşlem 3 bekler (blocking).
– Eğer işlem 1 veya işlem 2 commit/rollback yapana kadar İşlem 3 çalışamaz.
– Eğer SQL Server bir deadlock tespit ederse, işlemlerden birini iptal eder.
Ayrıca delete ve Insert komutlarını çalıştırdığımda aşağıdaki bekleme türleri görülmektedir.
Bu yüzden kilitlerin uyumluluğunu bilmek, performans ve ölçeklenebilirlik açısından kritik öneme sahiptir.

LCK_M_RIn_NL: Bir range insert kilidi almak için bekliyor ama NL (No Lock) modunda. Buradaki NL, aslında intent lock gibi çalışır; yani tabloya yeni bir değer insert ettiğini tablonun hoclock modunda yani Serializable izolasyon seviyesinde bulunmasından dolayıdır.

LCK_M_RS_S: Bir range shared (RS_S) kilidi almak için bekliyor. Bu kilit türü, genellikle bir aralıktaki verilerin okunması sırasında kullanılır.

Normal READ COMMITTED işlemlerinde tablo küçükse işlem biterse beklemez insert işlemi yapmaktadır. Normal bir SELECT cümlesinde (herhangi bir hint/ipucu kullanmadan), varsayılan olarak beklemez. INSERT işlemi rahatça yapılabilir.

Bunun nedenini ve aradaki kritik farkı şöyle açıklayabilirim:

SQL Server’da varsayılan izolasyon seviyesi genellikle Read Committed‘dır. Bu seviyede:

  • Kilit Süresi: Bir SELECT sorgusu bir satırı okuduğu anda üzerine geçici bir paylaşımlı kilit (Shared Lock) koyar, veriyi okur ve okuma biter bitmez kilidi hemen bırakır.
  • INSERT Durumu: SELECT sorgusu tüm tabloyu tarayıp bitirdikten sonra (milisaniyeler içinde), kilitler serbest kaldığı için INSERT işlemi hemen gerçekleşir. Hatta sorgu devam ederken bile, sorgunun henüz ulaşmadığı veya geçtiği satırlara INSERT yapılabilir.
  • Sonuç: Çakışma ihtimali çok düşüktür, birbirlerini engellemezler.

Diyelim ki bir Stok tablonuz var:

Sorgu TipiBirisi SELECT yaparken diğeri INSERT atabilir mi?Nedeni
Normal SELECTEvet, atabilir.Okuma biter bitmez kilitler çözülür.
HOLDLOCK ile SELECTHayır, bekler.Kilitler transaction sonuna kadar tutulur (Serializable).

Şu senaryoyu düşünün:

  1. Bir koltuğun boş olduğunu kontrol ettiniz (SELECT).
  2. O koltuğu rezerve edeceksiniz (INSERT/UPDATE).

Eğer normal SELECT kullanırsanız; siz kontrolü yaptıktan tam 1 milisaniye sonra başka biri araya girip o koltuğu kapabilir (çünkü kilidiniz hemen kalktı). HOLDLOCK ise “Ben bakıyorum, ben karar verene kadar kimse buraya dokunmasın” demektir.

Eğer amacınız sadece kilitlenmeleri önlemek ve veriyi hızlıca okumaksa;

  • Normal SELECT kullanın.
  • Hatta çok yoğun sistemlerde, okumanın hiçbir şeyi engellememesi için SET TRANSACTION ISOLATION LEVEL SNAPSHOT veya READ_COMMITTED_SNAPSHOT özelliklerini araştırmanızı öneririm.

Başka makale görüşmek dileğiyle..

Kalpler ancak Allah’ı anmakla huzura kavuşur. “ Ra’d Suresi; 28. Ayet

Author: Yunus YÜCEL

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir