SQL Server’da Intent Locks (Niyet Kilitleri), veritabanı motorunun kilit hiyerarşisini yönetmek için kullandığı bir “erken uyarı” mekanizmasıdır.
Bir kaynak üzerinde (örneğin bir satırda) kilit oluşturmadan önce, SQL Server bu kaynağın üst seviyelerine (Sayfa veya Tablo gibi) bir “niyet kilidi” koyar. Bu, diğer işlemlere “Aşağıdaki alt seviyelerde bir işlem yapıyorum, sakın bu tabloyu komple kilitlemeye kalkma!” mesajını verir.
Niyet kilitleri olmasaydı, SQL Server bir tabloyu tamamen kilitlemek (Tablo Kilidi – Schema Modification) istediğinde, o tablodaki binlerce satırı tek tek kontrol etmek zorunda kalırdı: “Acaba birisi bu satırı okuyor mu?” veya “Bu satırda bekleyen bir işlem var mı?”
Birkaç tipi vardır:
Intent Shared (IS): Şu an lock’lı durumda olan kaynaktan bir kısmını okuyacağını belirten lock tipidir. Lock bittiğinde Shared Lock koyarak ihtiyacı olan veriyi okur. Shared Lock koyduğunda Intent Shared Lock’ı kaldırmaz. İşi bittiğinde iki lock türünü beraber kaldırır.
Intent Exclusive (IX): Şu an lock’lı durumda olan kaynaktan bir kısmını değiştireceğini belirten lock tipidir. Lock bittiğinde Exclusive Lock koyarak ihtiyacı olan veriyi değiştirir. Exclusive Lock koyduğunda Intent Exlusive Lock’ı kaldırmaz. İşi bittiğinde iki lock türünü beraber kaldırır.
Shared With Intent Exlusive (SIX): Şu an lock’lı durumda olan kaynağın tamamını okuyacağını ve bir kısmını değiştireceğini belirten lock tipidir. Hem tablo düzeyinde Shared (S) kilidi hem de alt seviye kaynaklarda Exclusive (X) kilit alınacağını belirtir.
LCK_M_IX, bir işlemin Intent Exclusive (IX) kilidi almak için beklediğini gösterir. Bu, genellikle aşağıdaki durumlarda ortaya çıkar:
Niyet kilitleri sayesinde:
- SQL Server tablo seviyesine bakar.
- Eğer tabloda bir IX kilidi varsa, “Demek ki içeride birileri satır güncelliyor, tabloyu komple kilitleyemem” der ve bekler.
- Bu durum, devasa tabloların taranmasını engelleyerek performansı optimize eder.
Bir satırı güncellediğinizi düşünelim:
- Satır (Row): Özel Kilit (X) alır.
- Sayfa (Page): Niyet Özel Kilit (IX) alır.
- Tablo (Table): Niyet Özel Kilit (IX) alır.
Bu yapı sayesinde, başka bir kullanıcı aynı tabloda farklı bir satırı okumak isterse (IS kilidi ile), tablo seviyesindeki IX ve IS kilitleri birbirine uyumlu (compatible) olduğu için işlemine devam edebilir. Ancak biri tabloyu tamamen silmek veya yapısını değiştirmek isterse, IX kilidi buna engel olur.
Uyumluluk Matrisi
- IS ve IX: Birbirleriyle uyumludur. (Farklı satırlarda biri okuma biri yazma yapabilir).
- S (Shared) ve IX: Uyumsuzdur. (Biri tabloyu komple okumak istiyor, diğeri içeride bir yeri değiştiriyor).
- X (Exclusive) ve Herhangi Bir Intent: Uyumsuzdur.
SQL Server’ın niyet kilitlerini kullanmasındaki temel mantık, farklı seviyelerde çakışmaları önlemek ama aynı zamanda eşzamanlılığı (concurrency) artırmaktır.
Düşündüğünüz senaryoyu adım adım teknik olarak inceleyelim:
Aynı tabloda bir satır üzerinde bir kullanıcı okuma işlemi yapıyor. SELECT sorgusu çalıştırdığında (varsayılan Read Committed seviyesinde):
- Satır Seviyesi: Okuduğu satıra S (Shared) kilidi koyar.
- Tablo Seviyesi: Tabloya IS (Intent Shared) kilidi koyar.
- Mesajı: “Bu tablonun içinde bir yerlerde okuma yapıyorum, tablo şemasını değiştirme.”
2. Kullanıcı (Farklı Bir Satırı Güncelliyor):
Aynı tabloda farklı bir kullanıcı farklı bir satır üzerinde UPDATE sorgusu çalıştırdığında:
- Satır Seviyesi: Güncellediği satıra X (Exclusive) kilidi koyar.
- Tablo Seviyesi: Tabloya IX (Intent Exclusive) kilidi koyar.
- Mesajı: “Bu tablonun içinde bir yerlerde veri değiştiriyorum, tabloyu komple kilitleme.”
Yukarıdaki işlemlerde neden çakışma olmaz.
SQL Server’ın Lock Compatibility Matrix (Kilit Uyumluluk Matrisi) devreye girer:
| Mevcut Kilit | İstenen Kilit | Durum |
| IS | IX | Uyumlu (Compatible) |
| IS | S | Uyumlu |
| IX | IX | Uyumlu |
Tablo seviyesindeki IS ve IX kilitleri birbirine engel olmaz. Bu sayede SQL Server şunu anlar: “A kişisi içeride bir yerleri okuyor, B kişisi de içeride bir yerleri değiştiriyor. Farklı satırlarda oldukları sürece birbirlerini beklemelerine gerek yok.”
Bir tablonun tamamı üzerinde S kilidi varken (örneğin TABLOCK ipucuyla veya Serializable izolasyon seviyesinde büyük bir okuma yapılırken), başka bir kullanıcı tabloya IX (Intent Exclusive) koyamaz.
Bunun sebebi S ve IX kilitlerinin uyumsuz (incompatible) olmasıdır:
- S Kilidi: “Bu tablonun tamamını okuyorum, kimse içinde hiçbir şeyi değiştirmesin.” der.
- IX Kilidi: “Bu tablonun içinde bir yerleri değiştireceğim.” der.
Bu iki istek birbiriyle çeliştiği için SQL Server ikinci kullanıcıyı bekletir.
Bu şekilde Intent kilitleri olmasaydı ne olurdu. İkinci kullanıcı (Update yapan), tablonun içinde o an birinin okuma yapıp yapmadığını anlamak için tablodaki tüm satırları tek tek kontrol etmek zorunda kalırdı. Milyonlarca satırlık bir tabloda bu tam bir performans felaketi olurdu. Niyet kilitleri sayesinde sadece tablo seviyesindeki “etikete” bakması yeterli olur.
Özetle
Bir kullanıcı bir satırı okurken tabloya IS koyar, diğeri başka bir satırı güncellerken tabloya IX koyar. Bu iki kilit türü tablo seviyesinde “arkadaşça” geçindiği için her iki işlem de aynı anda, birbirini bloklamadan gerçekleşir.
Örnek bir senaryo üzerinde açıklayalım:
Bir işlem Bir satır üzerinde Exclusive (X) kilidi alır ve bir satırı tablo seviyesinde IX kilidi alarak günceller.
BEGIN TRAN;
UPDATE Sales.SalesOrderDetail SET OrderQty = 5 WHERE SalesOrderID = 43659;
COMMIT veya ROLLBACK yapılmadı satır seviyesinde X kilidi devam ediyor.
Başka bir işlem aynı tablonun farklı bir satırı üzerinde X kilidi almak ister ve Tablo seviyesinde Intent Exclusive (IX) kilidi koyar.
BEGIN TRAN;
UPDATE Sales.SalesOrderDetail SET OrderQty = 10 WHERE SalesOrderID = 50000;
Bu iki işlem arasındaki ilişkiyi teknik olarak şöyle özetleyebiliriz:
1. Tablo Seviyesindeki Durum (IX vs IX)
- 1. İşlem: Tabloya “Ben bu tablonun içinde bir satırı güncelliyorum” diyerek IX kilidi koyar.
- 2. İşlem: Tabloya “Ben de bu tablonun içinde (başka bir) satırı güncelliyorum” diyerek IX kilidi koyar.
- Sonuç: Tablo seviyesinde IX ile IX uyumludur. SQL Server, ikinci işlemin tabloya girmesine izin verir çünkü ikisi de “niyet” aşamasındadır ve tablonun tamamını kilitlemeye çalışmıyorlardır.
2. Satır Seviyesindeki Durum (X vs X)
- 1. İşlem:
SalesOrderID = 43659satırına X kilidi koyar. - 2. İşlem:
SalesOrderID = 50000satırına X kilidi koyar. - Sonuç: Her iki işlem de farklı satırlarda çalıştığı için birbirlerini asla engellemezler. İkisi de aynı anda başarıyla çalışır ve COMMIT bekler.
3. Bu Senaryoda sp_WhoIsActive Çıktısı Nasıl Görünür?
Eğer bu iki sorgu aynı anda çalışırken sp_WhoIsActive @get_locks = 1 derseniz:
- Her iki session’ı da “Running” (veya sleeping ama açık transaction ile) görürsünüz.
blocking_session_idsütunu ikisi için de boştur (çünkü bloklanma yok).- Kilit detaylarına (XML) baktığınızda, her ikisinin de aynı Tablo (OBJECT) üzerinde IX kilidi tuttuğunu ama farklı Satır (KEY) kaynakları üzerinde X kilidi tuttuğunu teyit edebilirsiniz.
Lock Escalation olayı nasıl gerçekleşir.
Eğer ikinci işleminiz 5-10 satırı değil de, tablodaki 5.000’den fazla satırı aynı anda güncellemeye çalışsaydı (veya tablo çok büyük olsaydı), SQL Server “Bu kadar çok satır kilidiyle uğraşamam” diyerek tablo seviyesindeki IX kilidini X kilidine yükseltmeye (Escalation) çalışabilirdi. İşte o zaman gerçek bir bloklanma yaşardınız.
Başka makalede görüşmek dileğiyle..
