
Site normal çalışıyor, sonra bir anda belirli bir işlem hata vermeye başlıyor. Veritabanı yavaş değil, disk boş, işlemci rahat — ama iki işlem birbirini bekliyor ve biri sonunda vazgeçiyor.
Bu yazı, veritabanı kilitlerini ve teşhisini ele alıyor.
Kilit Neden Var?
Kilitler bir arıza değil, tutarlılığın bedelidir:
- Aynı satırı iki işlem değiştiremez.
- Okuma sırasında veri değişmemelidir.
- İşlem tamamlanana kadar korunur.
Üçüncü madde sorunun kaynağını gösterir: bir kilit, işlem tamamlanana veya geri alınana kadar tutulur — yani uzun süren bir işlem, kilitlediği satırları o süre boyunca herkese kapatır.
Kilit süresini belirleyen şey sorgunun hızı değil, işlemin toplam uzunluğudur.
Kilit Türleri
| Tür | Etkisi |
|---|---|
| Paylaşımlı kilit | Başkaları okuyabilir, yazamaz |
| Özel kilit | Kimse dokunamaz |
| Satır kilidi | Yalnızca ilgili kayıt |
| Aralık kilidi | Satır aralığı |
| Tablo kilidi | Tüm tablo |
Dördüncü satır beklenmedik çakışmalar üretir: bir aralık kilidi, henüz var olmayan satırları bile kilitler — bu yüzden farklı kayıtlarla çalışan iki işlem birbirini beklemeye başlayabilir.
Bu davranış, yeni kayıt eklerken çakışma yaşanmasının nedenidir.
Beşinci satır ise en yıkıcı olanıdır ve genellikle eksik dizinden kaynaklanır; sonraki bölümde ele alınıyor.
Eksik Dizin ve Kilit
Aralarında doğrudan bir bağ vardır:
- Dizin yoksa tüm tablo taranır.
- Taranan her satır kilitlenir.
- Sonuçta tablonun tamamı kilitlenmiş olur.
Bu, çok kişinin bilmediği ama çok yaşadığı bir durumdur: tek bir satırı güncelleyen bir sorgu, o satırı bulmak için dizin kullanamıyorsa tablodaki tüm satırları kilitler — sanki tablo kilidi almış gibi davranır.
Bu nedenle kilit sorunlarının çözümü genellikle kilit ayarlarında değil, dizin eklemektedir.
Güncelleme ve silme sorgularının koşul sütunları mutlaka dizinli olmalıdır.
Ölü Kilit
İki işlem birbirini karşılıklı beklediğinde oluşur:
- A işlemi birinci kaydı kilitler.
- B işlemi ikinci kaydı kilitler.
- A ikinciyi ister, B birinciyi ister.
- İkisi de sonsuza kadar bekler.
Veritabanı bunu tespit eder ve birini feda eder: ölü kilit algılandığında veritabanı işlemlerden birini otomatik geri alır ve hata döndürür — bu bir arıza değil, kilitlenmeyi çözen normal bir davranıştır.
Uygulamanın bu hatayı yakalayıp işlemi tekrar denemesi gerekir.
Ölü kilidi önlemenin en etkili yolu, tüm işlemlerde kayıtlara aynı sırayla erişmektir. Sıralama tutarlıysa döngü oluşamaz.
Teşhis Etmek
| Kontrol | Ne gösterir |
|---|---|
| Çalışan işlem listesi | Kim ne bekliyor |
| Bekleyen kilitler görünümü | Engelleyen ve engellenen |
| Ölü kilit günlüğü | Son çakışmanın detayı |
| Uzun süren işlemler | Asıl suçlu |
Dördüncü satır çoğu vakayı çözer: dakikalarca açık kalan bir işlem, o süre boyunca kilitlerini tutar — ve genellikle o işlem bir sorgu değil, bekleyen bir uygulama kodudur.
İşlem açıkken bir dış servise istek göndermek, bir dosya işlemek veya kullanıcı girdisi beklemek bu duruma yol açar.
Üçüncü satır ise ölü kilitlerin hangi sorgular arasında yaşandığını açıkça gösterir ve düzeltmeyi kolaylaştırır.
Önleyici Uygulamalar
- İşlemleri kısa tutun.
- İşlem içinde dış servis çağırmayın.
- Kayıtlara tutarlı sırayla erişin.
- Koşul sütunlarını dizinleyin.
- Toplu işlemleri parçalayın.
İkinci madde en sık ihlal edilen kuraldır: bir işlem açıkken ödeme sağlayıcısına istek göndermek, o dış servis yavaşladığında veritabanı kilitlerinizi saniyelerce tutmanız demektir.
Doğru desen, dış çağrıyı işlem dışında yapmak ve sonucu ayrı bir kısa işlemle kaydetmektir.
Beşinci madde ise toplu güncellemelerde kritiktir. Yüz bin satırı tek işlemde güncellemek, o süre boyunca hepsini kilitler.
Yalıtım Seviyesi
Kilit davranışı ayarlanabilir:
- Daha gevşek seviye: Az kilit, daha az tutarlılık.
- Daha katı seviye: Çok kilit, tam tutarlılık.
Seviyeyi değiştirmek cazip görünür ama dikkatli olunmalıdır: yalıtım seviyesini düşürmek kilit sorunlarını azaltır ama okuduğunuz verinin doğruluğu konusunda yeni belirsizlikler yaratır.
Bir raporlama sorgusunda bu kabul edilebilir; bir ödeme işleminde değildir.
Doğru yaklaşım, seviyeyi genel olarak değiştirmek yerine yalnızca ihtiyaç duyulan sorgularda ayarlamaktır.
Kilit Yerine Kuyruk
Bazı senaryolarda kilit hiç gerekmez:
| Sorun | Alternatif çözüm |
|---|---|
| Sayaç güncelleme çakışması | Atomik artırma kullanın |
| Stok düşme yarışı | Koşullu güncelleme |
| Sıralı numara üretimi | Veritabanı sırası kullanın |
| Ağır toplu işlem | Kuyruğa alın |
İkinci satır çok değerli bir tekniktir: stok kontrolünü önce okuyup sonra yazmak yerine, "stok sıfırdan büyükse azalt" şeklinde tek bir koşullu güncelleme yapmak kilit ihtiyacını tamamen ortadan kaldırır.
Etkilenen satır sayısı sıfırsa stok yetersizdir; bu bilgi yarış koşulu olmadan elde edilir.
Birinci satır da benzer mantıkla çalışır ve okuma-yazma döngüsünü ortadan kaldırır.
Kilit ve bağlantı sorunlarını izlemek için veritabanı metriklerine erişmeniz gerekir; VDS sunucu kiralama ile tam yetkili erişim sayesinde bu görünümleri doğrudan sorgulayabilirsiniz.
Sonuç
Kilit sorunlarının çözümü genellikle kilit ayarlarında değildir: tek bir satırı güncelleyen bir sorgu, o satırı bulmak için dizin kullanamıyorsa tablodaki tüm satırları kilitler. İkinci en yaygın neden uzun işlemlerdir — özellikle işlem açıkken dış servise istek göndermek. Ölü kilit hatası bir arıza değildir; veritabanı kilitlenmeyi çözmek için birini feda eder ve uygulamanızın bu hatayı yakalayıp işlemi tekrar denemesi gerekir.
Sıkça Sorulan Sorular (SSS)
Tek satır güncelliyorum, neden kilit sorunu yaşıyorum?
Muhtemelen o satırı bulmak için dizin kullanılamıyor. Dizin yoksa tüm tablo taranır ve taranan her satır kilitlenir — sorgu sanki tablo kilidi almış gibi davranır. Güncelleme ve silme sorgularının koşul sütunları mutlaka dizinli olmalıdır.
Ölü kilit hatası aldım, ne yapmalıyım?
Bu bir arıza değil, veritabanının kilitlenmeyi çözme yöntemidir — işlemlerden birini geri alıp hata döndürür. Uygulamanız bu hatayı yakalayıp işlemi tekrar denemelidir. Önlemek için tüm işlemlerde kayıtlara aynı sırayla erişin; sıralama tutarlıysa döngü oluşamaz.
Kilitler neden bu kadar uzun tutuluyor?
Çünkü kilit süresini sorgunun hızı değil, işlemin toplam uzunluğu belirler. En sık neden, işlem açıkken bir dış servise istek göndermektir — o servis yavaşladığında kilitleri saniyelerce tutarsınız. Dış çağrıyı işlem dışında yapıp sonucu ayrı bir kısa işlemle kaydedin.
Kilitten tamamen kaçınabilir miyim?
Bazı senaryolarda evet. Stok düşerken önce okuyup sonra yazmak yerine "stok sıfırdan büyükse azalt" şeklinde tek bir koşullu güncelleme yapın — etkilenen satır sayısı sıfırsa stok yetersizdir ve bu bilgi yarış koşulu olmadan elde edilir. Sayaçlarda da atomik artırma kullanın.