SQL Server'da Kilit Yükseltme — Gün Sonu İşi Neden Müşteriyi Bekletti?
Önce şunu oku: MVCC ve Kilitler — Eski Satır Sürümleri Nerede Yaşar?
30 saniyede özet
SQL Server, tek bir ifade bir tabloda çok fazla satır kilidi aldığında bunları tek bir tablo kilidine çevirir. Böylece dokunulmayan satırlar da kilitlenir. Güncellemeyi eşiğin altında parçalara bölmek, tabloyu başkalarına açık tutar.
Kütüphaneci binlerce kitabı yeniden diziyor. Önce her rafa “meşgul” yazısı asıyor. Bir noktada bu kadar yazıyla uğraşmaktansa bütün salonun kapısına tek bir “kapalı” levhası asıyor.
-
Bayt: Gün sonu işi bütün hesapların pozisyonunu tek bir UPDATE ile yeniliyor. Tek satır SQL, ne güzel!
-
Sen: O sırada bir müşteri emir verdi. Pozisyon satırı güncellenemedi, dakikalarca bekledi.
-
Bayt: Ama gün sonu işi onun hesabına hiç dokunmuyordu!
-
Bayt: Dokunmuyordu. Peki tabloda kilitli olan neydi?
Satır kilidi, tablo kilidi
SQL Server bir satırı güncellerken o satırı kilitler; başka biri aynı satırı aynı anda değiştiremez. Diğer satırlar serbesttir.
Ama her kilit bellekte yer tutar. Tek bir ifade bir tabloda çok fazla kilit aldığında, SQL Server bunları tek bir tablo kilidine çevirir. Buna lock escalationSQL Server'ın, tek bir işlemin tuttuğu çok sayıda satır ya da sayfa kilidini daha az sayıda tablo kilidine çevirmesi. Bellek kazandırır, eşzamanlılığı azaltır.Sözlükte gör → denir.
Kafam karıştı, daha basit anlat
Az satırda satır kilitlenir. Çok satırda bütün tablo kilitlenebilir.
SQL Server bir satırı güncellerken ne kilitler?
Kilit yükseltme nedir?
Dokunmadığın satırlar da kilitli
Gün sonu işi tek bir UPDATE ile 12.000 satır güncelliyor. İş sürerken bir müşterinin emri, bu 12.000 satırın içinde olmayan bir satırı güncellemek istiyor. Bekler mi? Cevabı göster
Bekler. 12.000 satır kilidi yükseltme eşiğini aşar ve satır kilitleri tek bir tablo kilidine çevrilir. Müşterinin satırı işin içinde değildir, ama tablo kilitlidir; iş bitene kadar bekler.
Adım adım oku
- Binlerce kitap yeniden diziliyor.
- Çok fazla raf: bütün salon kapandı.
- Tek kitap isteyen kapıda bekliyor.
- Küçük parçalar: salon açık kalır.
Çözüm, büyük güncellemeyi eşiğin altında kalan parçalara bölmektir. Her parça kendi satırlarını kilitler, işini yapar ve onaylanır. Tablo hiç kilitlenmez; müşterinin satırı serbest kalır.
Kafam karıştı, daha basit anlat
Büyük güncellemeyi küçük parçalara böl ve her parçayı ayrı onayla.
Tek UPDATE 12.000 satırı güncellerken başka bir satırı güncellemek isteyen müşteri neden bekler?
Büyük bir güncellemenin kilit yükseltmesini önlemenin yaygın yolu nedir?
NOLOCK bir çözüm değil
Bekleyen sorgular için akla ilk gelen WITH (NOLOCK) olur. Okuyucu artık beklemez, ama kilitsiz okuduğu için yarım kalmış değişiklikleri görebilir. Sayfalar okunurken yer değiştirirse aynı satırı iki kez sayabilir ya da hiç göremez.
Okuyucuların yazanları beklememesi için daha güvenli yol, veritabanında satır sürümlemeSQL Server'da READ_COMMITTED_SNAPSHOT: okuyucu, yazanı beklemek yerine satırın onaylanmış son sürümünü okur. Yarım veriyi görmez.Sözlükte gör → açmaktır. Okuyucu, onaylanmış son sürümü görür; yazanı beklemez, yarım veriyi de görmez.
Kafam karıştı, daha basit anlat
NOLOCK yarım ve hatalı veri okutabilir. Okuyucular için satır sürümlemeyi kullan.
NOLOCK ile okumanın riski nedir?
Kendin gör
Gün sonu işi pozisyon tablosunu güncelliyor
Tohum 414688positions tablosu
○ kilit yok
Müşteri emri: · henüz gelmedi
Şu an ne oldu?
Kilit yok
Müşterinin satırı bu işin içinde değil. Yine de bekleyecek mi?
Görevler0/2
Müşteri, dokunulmayan satırı için beklesinaçık
İpucu
Tek bir büyük UPDATE.
Gün sonu işi bitsin, müşteri hiç beklemesinaçık
İpucu
Parçalara böl.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. Tek UPDATE tablo kilidine yükseldi; müşteri, işi bitene kadar iki tur bekledi.
- “4.000 satırlık üç parça”yı seç. Her parça eşiğin altında kaldı; müşteri geldiği anda güncelledi.
Simülatörde "4.000 satırlık üç parça" neden müşteriyi hiç bekletmedi?
Tuzaklar
Yarım kalan iş. Parçalara bölünen iş ortada kesilirse, bazı satırlar güncellenmiş, bazıları güncellenmemiş olur. İşi kaldığı yerden devam edebilecek şekilde yaz: hangi satırların bittiği belli olsun.
Yükseltmeyi kapatmak. Bir tablo için yükseltmeyi kapatmak mümkündür. Ama o zaman sunucu milyonlarca satır kilidi tutmak zorunda kalabilir ve belleği zorlanır; bunu ölçmeden yapma.
İndekssiz WHERE. Güncellemenin WHERE koşulu bir indeksle desteklenmiyorsa, SQL Server satırları bulmak için çok daha fazlasını tarar ve kilitler. Parçalama, iyi bir indeksle birlikte işe yarar.
Kafam karıştı, daha basit anlat
Parçalı işi kaldığı yerden sürdürülebilir yaz. Yükseltmeyi ölçmeden kapatma. WHERE’i indeksle destekle.
Parçalı gün sonu işi üçüncü parçada kesildi. Yeniden başlatınca ne olmalı?
Aşağıda gün sonu işinin parçalara bölünmüş hâli var: her döngüde en fazla 4.000 satır güncellenir ve onaylanır.
Derinleş · Gün sonu: pozisyon güncellemesi parça parça 3 dosya · ~35 satır · ilk okumada atlayabilirsin
Kendini sına
SQL Server çok fazla satır kilidini tek bir tablo kilidine çevirebilir.
Bir tablo için kilit yükseltmeyi tamamen kapatmanın riski nedir?
Aklında kalacak üç şey
- 1 Tek bir ifade bir tabloda çok fazla kilit alınca SQL Server satır kilitlerini tek bir tablo kilidine yükseltir. Artık dokunulmayan satırlar da kilitlidir.
- 2 Büyük bir güncellemeyi eşiğin altında kalan parçalara bölüp her parçayı ayrı onaylamak, yükseltmeyi önler ve başkalarının işini akıtır.
- 3 NOLOCK beklemeyi bitirir ama okunanı bozar: yarım kalmış, iki kez sayılmış ya da hiç sayılmamış satırlar okunabilir. Okuyucular için daha güvenli yol satır sürümlemedir.