MSSQL Server SNAPSHOT Isolation Level

MSSQL Server

Verileri anlık kopyalar ile okur, bu sayede diğer işlemler beklemez. İlk olarak veritabanı seviyesinde bu özelliğin aktif edilmesi gerekmektedir. Okuma tutarlılığı (read consistency) sağlamayı amaçlar. SI,  MVCC (Multi-Version Concurrency Control)mekanizmasını kullanarak, her işlem için verilerin bir “anlık görüntüsünü” (snapshot) oluşturur ve işlemlerin bu görüntüye göre çalışmasını sağlar. Database snapshot işleminin benzeri olarak karşımıza çıkmaktadır.

Snapshot Isolation’ın Temel İlkeleri

1. Anlık Görüntü (Snapshot) Mantığı
Bir transaction başladığında, veritabanındaki verilerin o anki haliyle bir anlık görüntüsü (snapshot) alınır. İşlem boyunca tüm SELECT işlemleri, bu görüntü üzerinden gerçekleştirilir.

2. Okuma (Read) Tutarlılığı
Okuma işlemleri, işlem başladığında alınan snapshot’taki verilere dayanır. Bu sayede, diğer işlemler tarafından yapılan güncellemeler işlem tamamlanana kadar görülmez.

3. Yazma (Write) Çatışmaları
Eğer bir işlem, belirli bir satırı değiştirmek isterse, bu satır başka bir işlem tarafından değiştirilmiş olabilir. SI altında, ilk yazan kazanır (first-writer-wins) prensibi geçerlidir. Yani, eğer bir işlem başka bir işlem tarafından güncellenmiş bir satırı değiştirmeye çalışırsa, hata (write conflict) alır ve işlemi geri alır (rollback).

ALTER DATABASE AdventureWorks2014 SET ALLOW_SNAPSHOT_ISOLATION ON;

Öncelikle, örnek verilerle bir tablo oluşturalım: 

CREATE TABLE Musteriler (
    MusteriID INT PRIMARY KEY IDENTITY(1,1),
    Ad VARCHAR(50),
    Bakiye DECIMAL(10,2)
);

INSERT INTO Musteriler (Ad, Bakiye) VALUES 
('Ahmet', 1000), 
('Mehmet', 2000), 
('Yunus', 3000);

Şimdi örnekler üzerinden SNAPSHOT Isolation Level seviyesini inceleyelim:

Transaction 1: Müşteri listesini okuyalım. Tablomuzu okuduktan sonra 10 saniye bekleyip diğer işlemlerimizi gerçekleştirip sonuçları gözlemleyelim.

SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRANSACTION
SELECT * FROM Musteriler;
WAITFOR DELAY '00:00:10';
SELECT * FROM Musteriler;
COMMIT;

Transaction 2: Ahmet’in bakiyesini güncelliyoruz. Güncelleme sonucunda Transaction 1 işlemi devam ederken işlemin gerçekleştiğini görüyoruz.

UPDATE Musteriler SET Bakiye = 1 WHERE MusteriID = 1;

Tablomuza select çektiğimizde güncelleme işlemimiz görünüyor. Transaction 1 devam etmektedir.

Transaction 1 işlemimiz devam ederken tablomuza insert işlemi gerçekleştirelim. Transaction 1 devam etmesine rağmen insert işlemi gerçekleşti.( Transaction 3)

insert into Musteriler(Ad,Bakiye)values('OKKES',1000)

Transaction 1 işlemimiz devam ederken tablomuza select çekelim:

Sonuç: 
Transaction 1, Transaction 2 ve Transaction 3’ün yaptığı değişiklikleri görmez. Kendi başlattığı anda var olan verinin bir kopyasını okur.  Transaction 1 işlemi bitmeden önce tablomuza select çektiğimizde insert ve update  değerlerinin döndüğünü görmüş oluyoruz.

Transaction 1 işlemi  sonuç döndüğünde yapılan değişiklikleri görmez.

Örnek olması açısında Transaction 1 işlemini tekrardan başlatıyorum. Bu süre zarfın MusteriID değeri 10 olan veriyi silip dönen sonuçları gözlemleyelim.

Transaction 1 işleminin devam ettiği sırada veri silme işlemi yapılır.

delete from  Musteriler where MusteriID=10

Transaction 1 işlemi sonuçlandıktan sonra snapshot üzerinden verilerin okunduğunu görmekteyiz.

Sql server üzerinde sys.databases komutu çalıştırdığınız snapshot_isolation_state durumu görünür. Veritabanı üzerinde bu özellik açıldığında veritabanı üzerinde her açılacak yeni bir sessionda yeni isolation seviyesine göre açılmasını saplıyacaktı. Bizden with(nolock) aynı yapıya denk gelir bu özelliği böyle kullanmamız daha mantıklı derlerse şöyle bir durum ortaya çıkar. Nolock dirty page’leri yani commit edilmemiş verileri okuma ihtimali var. Genellikle commit edilme ihtimali yüksek commit işlemi saniye dakika bazında gerçekleşir ama snapshot da ise sizin select sorgunuz 30 dakika sürebilir. Tablomuzda binlerce verinin değişmesi silinmesi ihtimali daha yüksektir. Bu da tutarsızlığı çok olan veriler üzerinde işlem yapmanız demek.
Örnek:
– Bir hastanede iki doktor var, her biri en az bir nöbette olmak zorunda.
– İlk işlem: Dr. A nöbetten çekilir, ama Dr. B hala nöbette olduğu için sorun yok.
– İkinci işlem: Dr. B de nöbetten çekilir, ama Dr. A’nın hala nöbette olduğunu düşünüyor.
– Sonuç: İki işlem de başarılı olur ama hastanede nöbette doktor kalmaz!
Anlık görüntüsüne bakarak sonuç dönderir. verinin eklendiği silindiğiyle ilgilenmez.

Aşağıdaki komutla default olan isolation level öğrenilir.

dbcc useroptions

Snapshot Isolation (SI) ve Read Committed Snapshot Isolation (RCSI) level seviyelerinde aşağıdaki farklılıklar bulunmaktadır.

1. TempDB Üzerinde Aşırı Yük (Version Store)
 RCSI:
Yüksek ve sürekli bir etki düzeyine sahiptir. Veritabanında RCSI açıldığı an, uygulamada hiçbir kod değişikliği olmasa bile varsayılan tüm okumalar Version Store’a yönlenir. Her UPDATE ve DELETE işleminde verinin eski sürümü tempdb’ye yazılır. Sürümler sadece aktif sorgu (statement) süresince tutulduğu için tempdb’deki versiyonların ömrü genellikle daha kısadır.
 SI:
 Etki düzeyi işlem yüküne bağlıdır. Sadece açıkça SET TRANSACTION ISOLATION LEVEL SNAPSHOT komutuyla başlatılan oturumlar için versiyon takibi hayati önem taşır. Sürümler tüm işlem (transaction) boyunca saklanmak zorundadır. Bir SI işlemi 2 saat sürerse, o 2 saat boyunca değişen tüm verilerin eski sürümleri tempdb’de kalır. Bu yüzden SI, tempdb’yi şişirme riski en yüksek modeldir.
2. Update Conflict (Güncelleme Çakışması)
 SI (Bunu Yaşar):
First-Committer-Wins ilkesiyle çalışır. A ve B işlemleri aynı satırı okuyup değiştirmek istediğinde, ilk COMMIT eden kazanır. İkinci işlem COMMIT etmeye çalıştığında SQL Server Error 3960 atar ve işlemi rollback eder.
Uygulama kodunda TRY…CATCH blokları ile bu hatayı yakalayıp işlemi yeniden deneyecek (Retry Logic) bir mimari şarttır.
 RCSI (Bunu YAŞAMAZ):
RCSI’da güncelleme çakışması hatası alınmaz.
Yazma işlemleri tıpkı geleneksel READ COMMITTED seviyesinde olduğu gibi karamsar kilitleri (Exclusive Lock) kullanır. İkinci işlem hata alıp iptal olmaz; ilk işlemin bitmesini kilit beklemesinde (Lock Wait) bekler ve ardından güncel veriyi işler.
3. Satır Başına 14 Bayt Depolama Maliyeti (Overhead)
 Hem SI Hem RCSI İçin Birebir Aynıdır:
 Veritabanı seviyesinde ALLOW_SNAPSHOT_ISOLATION ON veya READ_COMMITTED_SNAPSHOT ON seçeneklerinden herhangi biri açıldığı an, SQL Server ilgili veritabanındaki veri sayfalarında (Data Pages) güncellenen/eklenen her satırın sonuna 14 baytlık bir pointer (sürüm işaretçisi) ekler.
14 baytlık bu artış hem SI hem RCSI için geçerlidir. Page split, indeks fragmantasyonu ve Buffer Pool (RAM) alanının hızlı dolması riski her iki modelde de birebir eşittir.
4. Uzun Süren İşlemlerin (Long-running Transactions) Etkisi
 SI:
 Tehlike düzeyi çok yüksektir. SI, Transaction-level consistency sağladığı için, transaction başladığı andaki snapshot’ı korumak zorundadır. 3 saat süren bir SI transaction’ı varsa, SQL Server 3 saat boyunca sistemde değişen TÜM satırların eski sürümlerini tempdb’de tutar ve Garbage Collector bu sürümleri silemez (tempdb dolma riski).
 RCSI:
 Tehlikesi orta düzeydedir. RCSI, Statement-level consistency sağlar. Uzun süren bir transaction içinde bile olsanız, tamamlanan her bir SELECT sorgusunun ardından o sorgunun kullandığı versiyonlar boşa çıkar. Sadece uzun süren tek bir büyük SELECT sorgusu varsa tempdb temizliği bekler.
5. CPU ve Garbage Collection Maliyeti
 RCSI:
 Sürekli ve dengeli bir CPU yükü oluşturur. Sürümlerin ömrü kısa olduğu için Garbage Collector arka planda sık aralıklarla ve küçük parçalar halinde temizlik yapar.
 SI:
 Dalgalı CPU ve bellek yükü oluşturabilir. Uzun süren bir transaction bittiğinde, arka planda birikmiş devasa miktardaki Version Store kaydının temizlenmesi anlık CPU sıçramalarına (spikes) neden olabilir.

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

“Mutlu olanlar ise cennettedirler.” (Hud, 11/108)

Author: Yunus YÜCEL

Bir yanıt yazın

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