NOLOCK'un ötesi: row versioning, RCSI ve SQL Server 2025 optimized locking
NOLOCK'un gerçekte nasıl davrandığı (dirty read, atlanan ve iki kez okunan satırlar, 601 hatası), RCSI ve SNAPSHOT isolation'ın onun yerini nasıl aldığı ve SQL Server 2025 optimized locking'in üstüne neler kattığı, sınırlarıyla birlikte.
WITH (NOLOCK) genellikle yavaş bir raporun yazan transaction'ları beklemesini ya da onları bloklamasını önlemek için eklenir. İlk bakışta işe yarar, sorgu artık beklemez. Ama bedeli göründüğünden yüksek. NOLOCK altında bir sorgu sonradan rollback edilecek veriyi döndürebilir, var olan satırları atlayabilir, bazılarını iki kez sayabilir ya da tarama sırasında veri yer değiştirdiğinde 601 hatasıyla düşebilir.
SQL Server'ın okuyan/yazan blocking'ine uzun süredir daha iyi bir cevabı var, SQL Server 2025 ise bunun üstüne yeni bir katman ekliyor. Bu yazıda NOLOCK'un gerçekte ne yaptığını, RCSI ve SNAPSHOT ile row versioning'in onun yerini nasıl aldığını ve optimized locking'in bu tabloda nereye oturduğunu anlatıyorum.
NOLOCK'un gerçek davranışı
NOLOCK, READUNCOMMITTED ile aynı şey. Sorgu shared lock almaz ve diğer transaction'ların tuttuğu exclusive lock'lar tarafından bloklanmaz.
Dirty read kısmı iyi bilinir. Başka bir transaction'ın değiştirdiği satırı okursun, o transaction rollback olur ve sen resmen hiç var olmamış bir değeri göstermiş olursun.
Daha az bilinen sorun yapısal. Microsoft'un table hint dokümantasyonu bunu açıkça yazıyor: dirty read'lere izin vermek kullanıcıların "see records twice (or not at all)" durumuna, yani kayıtları iki kez görmesine ya da hiç görmemesine yol açabilir. Sebep fiziksel. NOLOCK altında motor allocation-order scan seçebilir. Bu tarama sayfaları index sırasına göre değil, ayrıldıkları sıraya göre okur. Sen tararken eşzamanlı bir insert ya da update page split'e yol açarsa, yeni sayfaya taşınan satırlar taramanın gerisine düşebilir (ve kaçırılır) ya da önüne geçebilir (ve tekrar okunur). Sistemdeki her transaction sonunda commit olsa bile SUM(amount) sonucun yanlış olabilir.
Bir de doğrudan hata durumu var. Veri bir NOLOCK taramasının altında yer değiştirirse sorgu 601 hatası ile düşebilir: "Could not continue scan with NOLOCK due to data movement." Dokümantasyon bunu deadlock'u (1205 hatası) ele aldığın gibi ele almanı, yani statement'ı tekrar denemeni öneriyor. Beklememek için eklediğin hint, artık retry mantığı yazmanı gerektiriyor.
Hint'in yapmadığı iki şey daha var:
- Bütün lock'lardan kaçınmaz.
NOLOCK'lu sorgular da Sch-S (schema stability) lock alır. Bu yüzden online olmayan bir index rebuild gibi Sch-M lock tutan DDL işlemleri tarafından bloklanırlar. - Yazma işlemlerine etkisi yoktur.
NOLOCK,INSERT,UPDATEya daDELETE'in hedef tablosuna uygulanamaz. OptimizerUPDATE/DELETE'in hedef tablosundaki hint'i yok sayar ve Microsoft bu kullanımın desteğinin kaldırılacağını duyurmuş durumda.
NOLOCK'un eski gerekçesi
NOLOCK, ana alternatifin lock tabanlı READ COMMITTED olduğu dönemden kalma. O dönemde uzun bir rapor gerçekten OLTP yazmalarını bloklar ya da onlar tarafından bloklanırdı. Row versioning SQL Server 2005'ten beri var. Bugün Azure SQL Database'de varsayılan davranış bu, SQL Server 2025 ise üstüne daha fazlasını inşa ediyor. NOLOCK'u haklı çıkaran ödünleşim artık geçerli değil.
RCSI ile row versioning
ALTER DATABASE Sales SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;
SELECT name, is_read_committed_snapshot_on
FROM sys.databases
WHERE name = N'Sales';
RCSI açıkken READ COMMITTED altında çalışan her statement, her satırın statement başladığı andaki son commit edilmiş versiyonunu okur. Okuyanlar shared lock almaz, dolayısıyla yazanları bloklamaz. Yazanlar da okuyanları bloklamaz. NOLOCK'un aksine commit edilmemiş veri görmezsin. Tarama sırasında yer değiştiren veriden kaynaklanan kayıp ya da çift satırlar da olmaz.
Bu geçiş veritabanına exclusive erişim ister, bu yüzden bir bakım penceresi planla. WITH ROLLBACK IMMEDIATE diğer oturumları sonlandırır.
RCSI'nin bedeli
- Version store. Güncellenen ve silinen satırların önceki versiyonları, onlara ihtiyaç duyan aktif bir statement kalmayana kadar saklanır. Accelerated database recovery (ADR) kapalıysa bu versiyonlar
tempdb'de tutulur. ADR açıksa (SQL Server 2019 ve sonrası) kullanıcı veritabanının içindeki persistent version store'a yazılır. Her iki durumda da uzun süren bir transaction temizliği durdurur, bunu izlemen gerekir. - Satır başına ek yük. Versiyonlanan satırlar versiyon bilgisi için fazladan byte taşır. Ayarı açtıktan hemen sonra bir miktar page split görebilirsin.
- Uygulamanın varsayımları. Asıl önemli kısım bu. Bir değeri okuyup ona göre yazan ve okumanın eşzamanlı yazan bitene kadar bekleyeceğini varsayan kod, artık bir önceki commit edilmiş versiyonu okuyor. Tipik örnekler: bakiyeyi kontrol edip sonra düşmek, ya da "bir sonraki boş numarayı SELECT et, sonra INSERT et". Bu kalıplar açık locking ister (
UPDLOCKya da atomik birUPDATE ... OUTPUT).READPASTkullanan kuyruk tabloları daREADCOMMITTEDLOCKeklemezsen RCSI altında hata verir.
SNAPSHOT isolation başka bir şey
ALTER DATABASE Sales SET ALLOW_SNAPSHOT_ISOLATION ON;
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRANSACTION;
-- buradaki her statement aynı ana ait görüntüyü görür
COMMIT;
RCSI her statement'a tutarlı bir görüntü verir. SNAPSHOT ise transaction'ın tamamına tek bir tutarlı görüntü verir. Birden çok sorgudan oluşan ve sonuçlarının birbiriyle tutarlı olması gereken raporlarda işe yarar. Oturumların SET TRANSACTION ISOLATION LEVEL SNAPSHOT ile bunu açıkça istemesi gerekir. Snapshot başladıktan sonra başka bir transaction'ın değiştirdiği bir satırı güncellemeye çalışan snapshot transaction'ı update conflict (3960 hatası) ile düşer. Bu yüzden onu kullanan yazma kodunun retry mantığına ihtiyacı var. Benim varsayılanım şu: veritabanı geneli için RCSI, SNAPSHOT ise yalnızca gerçekten tek bir tutarlı görüntüye ihtiyaç duyan transaction'larda.
SQL Server 2025: optimized locking
RCSI okuyan/yazan arasındaki blocking'i çözer. Yazan/yazan blocking'i ve lock belleği ise optimized locking'in konusu. Aşağıdakilerin hepsi Microsoft Learn'deki "Optimized locking" makalesinden.
Hangi platformda var?
- SQL Server 2025 (17.x): mevcut, varsayılan olarak kapalı, veritabanı bazında açılıyor.
- Azure SQL Database, Microsoft Fabric'teki SQL database ve Azure SQL Managed Instance (Always-up-to-date ya da SQL Server 2025 update policy ile): her zaman açık.
- SQL Server 2022 ve öncesi, ayrıca 2022 update policy ile çalışan Managed Instance: mevcut değil.
ALTER DATABASE Sales SET ACCELERATED_DATABASE_RECOVERY = ON;
ALTER DATABASE Sales SET OPTIMIZED_LOCKING = ON;
SELECT DATABASEPROPERTYEX(DB_NAME(), 'IsOptimizedLockingOn') AS is_optimized_locking_on;
ADR ön koşul. Önce onu açman gerekiyor ve optimized locking açıkken ADR'yi kapatamıyorsun.
Optimized locking iki parçadan oluşuyor:
- Transaction ID (TID) locking. Değişiklik sırasında row ve page lock'lar hâlâ alınıyor, ama her biri satır değiştirilir değiştirilmez bırakılıyor. Commit'e kadar tutulan tek lock, transaction ID'si üzerindeki tek bir
Xlock. Lock belleği ciddi şekilde düşüyor ve lock escalation ihtimali çok azalıyor. - Lock after qualification (LAQ). Predicate'ler,
Ulock alınmadan satırın son commit edilmiş versiyonu üzerinde değerlendiriliyor ve lock yalnızca koşulu sağlayan satırlara alınıyor. Farklı satırlara dokunan iki update artık birbirini bloklamıyor. LAQ yalnızca RCSI açıkken çalışıyor. Önce RCSI'yi açman için bir sebep daha.
Sınırlamalar ve davranış değişiklikleri
UPDLOCK,HOLDLOCK,XLOCKveREADCOMMITTEDLOCKgibi locking hint'lere uyuluyor, ama kazancı azaltıyorlar. Bu hint'leri taşıyan statement'larda LAQ kullanılmıyor.- LAQ şu durumlarda da kullanılmıyor:
MERGEstatement'ları,READ COMMITTEDdışındaki isolation level'lar, columnstore index'i olan tablolar, değişken ataması içeren DML ve sonuç kümesi döndüren ya da table variable'a yazanOUTPUTclause'ları. - Dokümantasyon bir davranış değişikliğini açıkça anlatıyor. RCSI ile birlikte LAQ açıkken,
UPDATE ... WHERE b = 2son commit edilmiş değere bakabilir ve eşzamanlı, henüz commit edilmemiş bir transaction'ın 2 yapmak üzere olduğu satırı atlayabilir. LAQ olmasaydı update bekler ve sonra o satırı değiştirirdi. İş yükün eşzamanlı transaction'lar arasında katı bir sıralamaya dayanıyorsa, Microsoft o transaction'lar içinREPEATABLE READya daSERIALIZABLEöneriyor. tempdbve temporary tablolar için, ayrıca read-only replica'larda kullanılmıyor.
Tuzaklar
- RCSI açmadan NOLOCK'u kaldırmak. Blocking geri gelir. Önce RCSI'yi aç ve test et, sonra hint'leri kaldır.
- Uzun transaction'ları gözden kaçırmak. Açık unutulmuş tek bir transaction, version store'un saatlerce büyümesine yol açabilir.
- View'ların içine gizlenmiş hint'ler. Bir view'ın içine yazılmış
NOLOCK, o view'ı kullanan her sorguya uygulanır. Bir view'a verilen lock hint de altındaki tablolara yayılır. Yalnızca uygulama kodunda değil, veritabanı nesnelerinde de ara. - Optimized locking'in açık olduğunu varsaymak. SQL Server 2025'te sen açana kadar kapalı. RCSI olmadan da LAQ devreye girmiyor.
Özet ve kontrol listesi
NOLOCK beklememek için doğruluktan vazgeçer. Row versioning ise bu ödünleşimi gereksiz kılar. Asıl derdin okuyanların yazanları bloklamasıysa RCSI'yi aç ve hint'leri kaldır. Tek bir tutarlı görüntüye ihtiyaç duyan transaction'larda SNAPSHOT kullan. SQL Server 2025'te ise yazanlar arasındaki blocking'i de azaltmak için optimized locking'i ekle.
- Kodda, view'larda ve procedure'larda geçen bütün
NOLOCKveREADUNCOMMITTED'ları bul. - Önce okuyup sonra yazan kalıpları ve
READPASTkullanan kuyrukları RCSI uyumluluğu açısından gözden geçir. - Bir bakım penceresinde
READ_COMMITTED_SNAPSHOT'ı aç ve version store'u izle. - Hint'leri kaldır ve blocking'i öncesi ve sonrası için ölç.
- Birden çok statement boyunca tek bir tutarlı görüntüye ihtiyaç duyan transaction'larda
SNAPSHOTkullan. - SQL Server 2025'te önce ADR'yi, ardından
OPTIMIZED_LOCKING'i aç. Sık çalışan kod yollarını gereksiz locking hint'lerden arındır.
- ---
- baslik: "NOLOCK'un ötesi: row versioning, RCSI ve SQL Server 2025 optimized locking"
- ozet: "NOLOCK'un gerçekte nasıl davrandığı (dirty read, atlanan ve iki kez okunan satırlar, 601 hatası), RCSI ve SNAPSHOT isolation'ın onun yerini nasıl aldığı ve SQL Server 2025 optimized locking'in üstüne neler kattığı, sınırlarıyla birlikte."
- tarih: 2026-09-17
- etiketler:
- - sql-server
- - concurrency
- - performance
- kategoriler:
- - veritabani
- ---
- `WITH (NOLOCK)` genellikle yavaş bir raporun yazan transaction'ları beklemesini ya da onları bloklamasını önlemek için eklenir. İlk bakışta işe yarar, sorgu artık beklemez. Ama bedeli göründüğünden yüksek. `NOLOCK` altında bir sorgu sonradan rollback edilecek veriyi döndürebilir, var olan satırları atlayabilir, bazılarını iki kez sayabilir ya da tarama sırasında veri yer değiştirdiğinde 601 hatasıyla düşebilir.
- SQL Server'ın okuyan/yazan blocking'ine uzun süredir daha iyi bir cevabı var, SQL Server 2025 ise bunun üstüne yeni bir katman ekliyor. Bu yazıda `NOLOCK`'un gerçekte ne yaptığını, RCSI ve SNAPSHOT ile row versioning'in onun yerini nasıl aldığını ve optimized locking'in bu tabloda nereye oturduğunu anlatıyorum.
- ## NOLOCK'un gerçek davranışı
- `NOLOCK`, `READUNCOMMITTED` ile aynı şey. Sorgu shared lock almaz ve diğer transaction'ların tuttuğu exclusive lock'lar tarafından bloklanmaz.
- Dirty read kısmı iyi bilinir. Başka bir transaction'ın değiştirdiği satırı okursun, o transaction rollback olur ve sen resmen hiç var olmamış bir değeri göstermiş olursun.
- Daha az bilinen sorun yapısal. Microsoft'un table hint dokümantasyonu bunu açıkça yazıyor: dirty read'lere izin vermek kullanıcıların "see records twice (or not at all)" durumuna, yani kayıtları iki kez görmesine ya da hiç görmemesine yol açabilir. Sebep fiziksel. `NOLOCK` altında motor allocation-order scan seçebilir. Bu tarama sayfaları index sırasına göre değil, ayrıldıkları sıraya göre okur. Sen tararken eşzamanlı bir insert ya da update page split'e yol açarsa, yeni sayfaya taşınan satırlar taramanın gerisine düşebilir (ve kaçırılır) ya da önüne geçebilir (ve tekrar okunur). Sistemdeki her transaction sonunda commit olsa bile `SUM(amount)` sonucun yanlış olabilir.
- Bir de doğrudan hata durumu var. Veri bir `NOLOCK` taramasının altında yer değiştirirse sorgu **601 hatası** ile düşebilir: "Could not continue scan with NOLOCK due to data movement." Dokümantasyon bunu deadlock'u (1205 hatası) ele aldığın gibi ele almanı, yani statement'ı tekrar denemeni öneriyor. Beklememek için eklediğin hint, artık retry mantığı yazmanı gerektiriyor.
- Hint'in yapmadığı iki şey daha var:
- - Bütün lock'lardan kaçınmaz. `NOLOCK`'lu sorgular da Sch-S (schema stability) lock alır. Bu yüzden online olmayan bir index rebuild gibi Sch-M lock tutan DDL işlemleri tarafından bloklanırlar.
- - Yazma işlemlerine etkisi yoktur. `NOLOCK`, `INSERT`, `UPDATE` ya da `DELETE`'in hedef tablosuna uygulanamaz. Optimizer `UPDATE`/`DELETE`'in hedef tablosundaki hint'i yok sayar ve Microsoft bu kullanımın desteğinin kaldırılacağını duyurmuş durumda.
- ## NOLOCK'un eski gerekçesi
- `NOLOCK`, ana alternatifin lock tabanlı `READ COMMITTED` olduğu dönemden kalma. O dönemde uzun bir rapor gerçekten OLTP yazmalarını bloklar ya da onlar tarafından bloklanırdı. Row versioning SQL Server 2005'ten beri var. Bugün Azure SQL Database'de varsayılan davranış bu, SQL Server 2025 ise üstüne daha fazlasını inşa ediyor. `NOLOCK`'u haklı çıkaran ödünleşim artık geçerli değil.
- ## RCSI ile row versioning
- ```sql
- ALTER DATABASE Sales SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;
- SELECT name, is_read_committed_snapshot_on
- FROM sys.databases
- WHERE name = N'Sales';
- ```
- RCSI açıkken `READ COMMITTED` altında çalışan her statement, her satırın **statement** başladığı andaki son commit edilmiş versiyonunu okur. Okuyanlar shared lock almaz, dolayısıyla yazanları bloklamaz. Yazanlar da okuyanları bloklamaz. `NOLOCK`'un aksine commit edilmemiş veri görmezsin. Tarama sırasında yer değiştiren veriden kaynaklanan kayıp ya da çift satırlar da olmaz.
- Bu geçiş veritabanına exclusive erişim ister, bu yüzden bir bakım penceresi planla. `WITH ROLLBACK IMMEDIATE` diğer oturumları sonlandırır.
- ### RCSI'nin bedeli
- - **Version store.** Güncellenen ve silinen satırların önceki versiyonları, onlara ihtiyaç duyan aktif bir statement kalmayana kadar saklanır. Accelerated database recovery (ADR) kapalıysa bu versiyonlar `tempdb`'de tutulur. ADR açıksa (SQL Server 2019 ve sonrası) kullanıcı veritabanının içindeki persistent version store'a yazılır. Her iki durumda da uzun süren bir transaction temizliği durdurur, bunu izlemen gerekir.
- - **Satır başına ek yük.** Versiyonlanan satırlar versiyon bilgisi için fazladan byte taşır. Ayarı açtıktan hemen sonra bir miktar page split görebilirsin.
- - **Uygulamanın varsayımları.** Asıl önemli kısım bu. Bir değeri okuyup ona göre yazan ve okumanın eşzamanlı yazan bitene kadar bekleyeceğini varsayan kod, artık bir önceki commit edilmiş versiyonu okuyor. Tipik örnekler: bakiyeyi kontrol edip sonra düşmek, ya da "bir sonraki boş numarayı SELECT et, sonra INSERT et". Bu kalıplar açık locking ister (`UPDLOCK` ya da atomik bir `UPDATE ... OUTPUT`). `READPAST` kullanan kuyruk tabloları da `READCOMMITTEDLOCK` eklemezsen RCSI altında hata verir.
- ### SNAPSHOT isolation başka bir şey
- ```sql
- ALTER DATABASE Sales SET ALLOW_SNAPSHOT_ISOLATION ON;
- SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
- BEGIN TRANSACTION;
- -- buradaki her statement aynı ana ait görüntüyü görür
- COMMIT;
- ```
- RCSI her statement'a tutarlı bir görüntü verir. `SNAPSHOT` ise transaction'ın tamamına tek bir tutarlı görüntü verir. Birden çok sorgudan oluşan ve sonuçlarının birbiriyle tutarlı olması gereken raporlarda işe yarar. Oturumların `SET TRANSACTION ISOLATION LEVEL SNAPSHOT` ile bunu açıkça istemesi gerekir. Snapshot başladıktan sonra başka bir transaction'ın değiştirdiği bir satırı güncellemeye çalışan snapshot transaction'ı update conflict (3960 hatası) ile düşer. Bu yüzden onu kullanan yazma kodunun retry mantığına ihtiyacı var. Benim varsayılanım şu: veritabanı geneli için RCSI, `SNAPSHOT` ise yalnızca gerçekten tek bir tutarlı görüntüye ihtiyaç duyan transaction'larda.
- ## SQL Server 2025: optimized locking
- RCSI okuyan/yazan arasındaki blocking'i çözer. Yazan/yazan blocking'i ve lock belleği ise **optimized locking**'in konusu. Aşağıdakilerin hepsi Microsoft Learn'deki "Optimized locking" makalesinden.
- **Hangi platformda var?**
- - **SQL Server 2025 (17.x):** mevcut, **varsayılan olarak kapalı**, veritabanı bazında açılıyor.
- - **Azure SQL Database, Microsoft Fabric'teki SQL database ve Azure SQL Managed Instance** (Always-up-to-date ya da SQL Server 2025 update policy ile): her zaman açık.
- - **SQL Server 2022 ve öncesi**, ayrıca 2022 update policy ile çalışan Managed Instance: mevcut değil.
- ```sql
- ALTER DATABASE Sales SET ACCELERATED_DATABASE_RECOVERY = ON;
- ALTER DATABASE Sales SET OPTIMIZED_LOCKING = ON;
- SELECT DATABASEPROPERTYEX(DB_NAME(), 'IsOptimizedLockingOn') AS is_optimized_locking_on;
- ```
- ADR ön koşul. Önce onu açman gerekiyor ve optimized locking açıkken ADR'yi kapatamıyorsun.
- Optimized locking iki parçadan oluşuyor:
- - **Transaction ID (TID) locking.** Değişiklik sırasında row ve page lock'lar hâlâ alınıyor, ama her biri satır değiştirilir değiştirilmez bırakılıyor. Commit'e kadar tutulan tek lock, transaction ID'si üzerindeki tek bir `X` lock. Lock belleği ciddi şekilde düşüyor ve lock escalation ihtimali çok azalıyor.
- - **Lock after qualification (LAQ).** Predicate'ler, `U` lock alınmadan satırın son commit edilmiş versiyonu üzerinde değerlendiriliyor ve lock yalnızca koşulu sağlayan satırlara alınıyor. Farklı satırlara dokunan iki update artık birbirini bloklamıyor. **LAQ yalnızca RCSI açıkken çalışıyor.** Önce RCSI'yi açman için bir sebep daha.
- ### Sınırlamalar ve davranış değişiklikleri
- - `UPDLOCK`, `HOLDLOCK`, `XLOCK` ve `READCOMMITTEDLOCK` gibi locking hint'lere uyuluyor, ama kazancı azaltıyorlar. Bu hint'leri taşıyan statement'larda LAQ kullanılmıyor.
- - LAQ şu durumlarda da kullanılmıyor: `MERGE` statement'ları, `READ COMMITTED` dışındaki isolation level'lar, columnstore index'i olan tablolar, değişken ataması içeren DML ve sonuç kümesi döndüren ya da table variable'a yazan `OUTPUT` clause'ları.
- - Dokümantasyon bir **davranış değişikliğini** açıkça anlatıyor. RCSI ile birlikte LAQ açıkken, `UPDATE ... WHERE b = 2` son commit edilmiş değere bakabilir ve eşzamanlı, henüz commit edilmemiş bir transaction'ın 2 yapmak üzere olduğu satırı atlayabilir. LAQ olmasaydı update bekler ve sonra o satırı değiştirirdi. İş yükün eşzamanlı transaction'lar arasında katı bir sıralamaya dayanıyorsa, Microsoft o transaction'lar için `REPEATABLE READ` ya da `SERIALIZABLE` öneriyor.
- - `tempdb` ve temporary tablolar için, ayrıca read-only replica'larda kullanılmıyor.
- ## Tuzaklar
- - **RCSI açmadan NOLOCK'u kaldırmak.** Blocking geri gelir. Önce RCSI'yi aç ve test et, sonra hint'leri kaldır.
- - **Uzun transaction'ları gözden kaçırmak.** Açık unutulmuş tek bir transaction, version store'un saatlerce büyümesine yol açabilir.
- - **View'ların içine gizlenmiş hint'ler.** Bir view'ın içine yazılmış `NOLOCK`, o view'ı kullanan her sorguya uygulanır. Bir view'a verilen lock hint de altındaki tablolara yayılır. Yalnızca uygulama kodunda değil, veritabanı nesnelerinde de ara.
- - **Optimized locking'in açık olduğunu varsaymak.** SQL Server 2025'te sen açana kadar kapalı. RCSI olmadan da LAQ devreye girmiyor.
- ## Özet ve kontrol listesi
- `NOLOCK` beklememek için doğruluktan vazgeçer. Row versioning ise bu ödünleşimi gereksiz kılar. Asıl derdin okuyanların yazanları bloklamasıysa RCSI'yi aç ve hint'leri kaldır. Tek bir tutarlı görüntüye ihtiyaç duyan transaction'larda `SNAPSHOT` kullan. SQL Server 2025'te ise yazanlar arasındaki blocking'i de azaltmak için optimized locking'i ekle.
- 1. Kodda, view'larda ve procedure'larda geçen bütün `NOLOCK` ve `READUNCOMMITTED`'ları bul.
- 2. Önce okuyup sonra yazan kalıpları ve `READPAST` kullanan kuyrukları RCSI uyumluluğu açısından gözden geçir.
- 3. Bir bakım penceresinde `READ_COMMITTED_SNAPSHOT`'ı aç ve version store'u izle.
- 4. Hint'leri kaldır ve blocking'i öncesi ve sonrası için ölç.
- 5. Birden çok statement boyunca tek bir tutarlı görüntüye ihtiyaç duyan transaction'larda `SNAPSHOT` kullan.
- 6. SQL Server 2025'te önce ADR'yi, ardından `OPTIMIZED_LOCKING`'i aç. Sık çalışan kod yollarını gereksiz locking hint'lerden arındır.