MSSQL Server’da Shared(S) Lock Nedir

SQL Server dünyasında Shared Lock (S), yani “Paylaşılan Kilit,” veritabanı tutarlılığını sağlamak için kullanılan en temel kilit türlerinden biridir. Genellikle bir veri okunurken (SELECT işlemi) devreye girer.

Okuma (SELECT) işlemleri için kullanılan kilittir. Birden fazla kullanıcı aynı anda aynı satırı okuyabilir. Çünkü shared lock birbirini engellemez ama insert-update-delete işlemlerini  yapamaz. İlgili güncellemelerin yapılması için exclusive lock koyulması gerekmektedir.

Veri okuma bittiğinde lock bırakılır. Pessimistic  concurrency control yapısını kullanmaktadır. Shared lock olan diğer satırlar dışındaki satırlara başka kullanıcılar INSERT, UPDATE, DELETE yapabilir. Sadece ilgili satır, bölüm veya page’e bir müdahalede bulunamazlar.

Aşağıdaki tablo, bir kaynak üzerinde kilit varken ikinci bir kilidin gelmesi durumunda ne olacağını özetler:

Mevcut Kilitİstenen KilitDurumAçıklama
Shared (S)Shared (S)İzin Verilirİki kişi aynı anda okuma yapabilir.
Shared (S)Exclusive (X)BekletilirOkuma bitmeden veri güncellenemez.
Exclusive (X)Shared (S)BekletilirGüncelleme bitmeden veri okunamaz.

Eğer NOLOCK (Read Uncommitted) hint’ini kullanırsanız, SQL Server bu S-Lock mekanizmasını görmezden gelir. Bu hız kazandırır ama “Dirty Read” dediğimiz hatalı/hayalet verileri okumanıza sebep olabilir.

Satır Bazlı Kilit (Row-Level Locking)

SQL Server genellikle çok akıllıdır ve sadece okuduğunuz satırlara kilit koyar.

  • Siz Tablo A’daki mevcut 100 satırı okuyorsanız, SQL Server bu satırlara Shared (S) Lock koyar.
  • O sırada başka biri aynı tabloya 101. satırı INSERT etmek isterse, SQL Server buna izin verir.
  • Çünkü yeni eklenecek veri, sizin kilitlediğiniz mevcut satırlarla çakışmaz.

Tablo Bazlı Kilit (Table-Level Locking)

Eğer Shared Lock tüm tabloyu kapsıyorsa (Table Lock), o zaman işler değişir.

  • Eğer sorgunuzda TABLOCK hint’i kullandıysanız (Örn: SELECT * FROM Tablo WITH (TABLOCK)) veya SQL Server binlerce satırı okuduğu için kilitleri otomatik olarak tablo seviyesine yükselttiyse (Lock Escalation), tablonun tamamına S-Lock konulur.
  • Bu durumda tabloya INSERT yapılamaz. Çünkü INSERT işlemi için tablonun bütününde veya ilgili sayfasında bir Intent Exclusive (IX) kilidi gerekir ve S-Lock ile IX-Lock birbiriyle uyumsuzdur.

Şimdi Örnek üzerinden yukarıdaki ifadelerin ne olduğunu gözlemleyelim

Şimdi bir shared lock oluşturup tablomuzun üzerinde işlemleri gözlemleyelim. Kullanıcı sadece belirli bir satırdaki veriyi okuyacak. Diğer satılarda update insert delete yapıldığını görmüş olacağız. Resimde dikkat ederseniz 1. ve 2. veri satırı üzerinde işlem yapılmaktadır.

BEGIN TRAN
Select* from Musteriler WHERE MusteriID =1;
BEGIN TRAN
Select* from Musteriler WHERE MusteriID =2;

3. satıra update işlemi olduğunda güncellendiğini görmekteyiz. Çünkü lock’lama tablo seviyesinde değil satır seviyesindedir.

UPDATE Musteriler SET Bakiye = 0 WHERE MusteriID =3;

Aşağıdaki insert işleminin de başarılı bir bir şekilde insert edildiği görülmektedir. Çünkü lock’lama tablo seviyesinde değil satır seviyesindedir.

INSERT INTO Musteriler(Ad,Bakiye) Values('ELEL',2323)

Kısacası select çekilen row-page-aralık dışındaki veriler üzerinde güncelleme veya başka bir işlem yapılabilmektedir.

SELECT * FROM Customers WITH (NOLOCK); → Bu komut, Shared Lock kullanmaz, okuma sırasında başka işlemler engellenmez. İlgili satırda başka kullanıcı insert/update/delete yapabilir. Read uncommitted isolation level seviyesini desteklemektedir. Dirty page non reaptable read ve phantom read okumalarına sebebiyet vermektedir.

Aşağıdaki komutta  kullanıcı Shared (S) Lock ile veri okuyor:

USE AdventureWorks2014; 
GO 
BEGIN TRAN 
SELECT * FROM Sales.SalesOrderDetail WHERE OrderQty = 10; 
WAITFOR DELAY '00:00:10'; -- 10 saniye beklet (kilidi serbest bırakma) 
COMMIT;

Bu işlem, OrderQty = 10 olan satır üzerinde Shared (S) Lock oluşturur. Başka bir kullanıcı  delay komutuyla belirtilmiş süre zarfı içerisinde aynı tablo ve koluna  SELECT Çekiyor. İlk kullanıcının delay komutuyla select ifadesine shared lock koymasına rağmen ikinci kullanıcı aynı veriyi okur ve  ilk kullanıcı ikinci kullanıcının çalışmasına  engel olmaz  çünkü Shared Lock’lar birbirini engellemez.

USE AdventureWorks2014;
GO
SELECT * FROM Sales.SalesOrderDetail WHERE OrderQty = 10;

Aşağıdaki sorguda ise yukarıdaki kodda delay komutuyla belirtilmiş süre zarfı içerisinde aynı tablo ve kolonunu   OrderQty = 10 olan satırları güncellemek ister. Ancak, İşlemler bitmeden çalışmaz çünkü UPDATE işlemi Exclusive (X) Lock gerektirir ve Shared Lock bunu engeller. Yukarıdaki sorguda herhangi isolation level belirtilmemişse Read committed isolation level kullanılır.  OrderQty = 10 satırı dışında herhangi bir satır üzerinde güncelleme işlemi yapılır.

USE AdventureWorks2014;
GO
BEGIN TRAN
UPDATE Sales.SalesOrderDetail SET OrderQty = 15 WHERE OrderQty = 10;
COMMIT;

Yukarıdaki işlemde  sql üzerinde default olan Read committed isolation level seviyesini desteklediği için Shared lock ifadesi aldığı için yukarıdaki komut güncelleme işlemini yapmamaktadır. Güncelleme işlemi yapılmaması için ayrıca Repeatable read vb. isolation seviyelerinin kullanılması gerekmektedir. Bu isolation level seviyesinde delete ve güncellenme işlemi yapılmaz. Yukarıdaki örneklerle deneye bilirsiniz.

NOLOCK kullanıldığında:

  • Başka işlemler satırı update/delete edebilir.
  • Bu, dirty read’e neden olabilir (okunan veri henüz commit edilmemiş olabilir, yani rollback bile edilebilir).
  • Satır okunduğu anda başka bir transaction onu değiştirmiş olabilir.

Herhangi bir satırda veya page’de exclusive lock varsa son kullanıcı WITH (NOLOCK) ile gelirse exclusive lock olan page veya satırı da okumaktadır.

  • WITH (NOLOCK), mevcut exclusive lock’ları yok sayar ve kilitli veri sayfasına erişmeye çalışır.
  • Ancak bazı özel durumlarda (özellikle yüksek trafikli sistemlerde veya büyük transaction’larda):
    • Eğer sayfa hareket halindeyse (örneğin page split oluyor ya da başka bir işlem fiziksel yapıyı değiştiriyor),
    • SQL Server veri bütünlüğünü korumak için geçici olarak erişimi engelleyebilir.
    • Bu durumda WITH (NOLOCK) bile o an için veriye ulaşamayabilir ya da hatalı/eksik/çift veri okuyabilir.

Yani WITH (NOLOCK), genellikle exclusive lock’ları da aşarak okuma yapar, ama bu veri tutarlılığı açısından risklidir ve her zaman başarılı olacağı garantilenemez.

Başlangıç ve Shared Lock Durumu

Burada begin tran diyerek bir işlem başlatmış ve MusteriID = 1 olan satırı okunmuş.

  • Analiz: SQL Server’ın varsayılan izolasyon seviyesinde (Read Committed), bir SELECT işlemi biter bitmez üzerindeki Shared (S) Lock kalkar.
  • Resimde sadece SELECT çekip beklediğin için, aslında bu işlem bittiği an kilit serbest bırakıldı. Yani şu an tablonun o satırı üzerinde aktif bir kilit bulunmuyor (çünkü sorgu tamamlanmış görünüyor). İster begin tran devam etsin.

Başarılı Update (Kilit Yok)

Burada MusteriID = 1 için bakiyeyi 789 olarak başarılı bir şekilde güncellenir

1. resimdeki sorgu sadece bir okuma işlemiydi ve bittiği anda kilidini bıraktı. 2. resimdeki UPDATE komutu geldiğinde satır “boşta” olduğu için SQL Server hemen Exclusive (X) Lock alabildi ve işlemi tamamladı. Burada BEGIN TRANSACTION yapılmış ama COMMIT veya ROLLBACK olmamış. Bu şu demek: 2. resimdeki işlem şu an o satırı rehin tutuyor! Satır üzerinde şu an bir Exclusive Lock var.

Yukarıdaki resimde işlemin gerçekleşmediğini, yani sorgunun “takılı kaldığını” (Executing query…) görüyorsun. Neden gerçekleşmiyor: Çünkü 2. resimde başlattığın işlem hala açık (açık bir transaction var). 2. resim o satıra “Bu satır benim, ben işimi bitirene kadar kimse dokunamaz” (Exclusive Lock) dedi. 3. resimdeki UPDATE komutu, 2. resimdeki işlemin ya COMMIT (onay) ya da ROLLBACK (iptal) edilmesini bekliyor. SQL Server veri tutarlılığını korumak için 3. kişinin aynı anda aynı satırı değiştirmesine izin vermiyor.

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

“Şüphesiz güçlükle beraber bir kolaylık vardır. Gerçekten, güçlükle beraber bir kolaylık vardır.”  İnşirah Suresi; 5-6. Ayet

Author: Yunus YÜCEL

Bir yanıt yazın

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