Takip et

SQL’de İşlemler, Kilitlenmeler ve Günlük Tabanlı Kurtarma Yönetimi

Veritabanı sistemleri, modern uygulamaların bel kemiğidir ve veri tutarlılığı, erişilebilirliği ile güvenilirliği kritik öneme sahiptir. Peki, birden fazla kullanıcının aynı anda veri üzerinde işlem yaptığı durumlarda veri bütünlüğünü nasıl sağlıyoruz? İşte bu sorunun cevabı, SQL’deki işlemler (transactions), kilitlenmeler (deadlocks) ve günlük tabanlı kurtarma (log-based recovery) mekanizmalarında gizlidir. Bu makalede, bu temel kavramları baştan sona ele alacak, karşılaşabileceğiniz sorunları ve çözüm yollarını gerçek dünya senaryolarıyla adım adım inceleyeceğiz. Amacımız, veritabanı yönetimini daha iyi anlamanıza ve sistemlerinizi daha sağlam hale getirmenize yardımcı olmaktır.

SQL veritabanı sistemlerinde, bir işlem (transaction) tek bir mantıksal çalışma birimi olarak tanımlanır. Bu, bir dizi veritabanı işleminin (INSERT, UPDATE, DELETE gibi) ya tamamen başarıyla tamamlandığı (commit edildiği) ya da hiçbirinin gerçekleşmemiş gibi geri alındığı (rollback edildiği) anlamına gelir. Peki, neden bu kadar önemli? Çünkü veri tutarlılığı, özellikle eşzamanlı olarak birçok kullanıcının veritabanına eriştiği sistemlerde, işlemler olmadan sağlanamaz. Bir banka hesabından diğerine para transferi gibi karmaşık operasyonları düşünün; bu işlem, alıcının hesabına para eklenmeden önce göndericinin hesabından para çekilirse, bir felaketle sonuçlanabilir. İşlemler, tam da bu tür durumları önlemek için tasarlanmıştır.

ACID Özellikleri: İşlemlerin Temel Taşları Nelerdir?

İşlemlerin güvenilirliğini ve tutarlılığını sağlayan dört ana özellik vardır. Bunlar, kısaca ACID olarak adlandırılır:

  • Atomicity (Atomiklik): Bir işlemdeki tüm adımlar ya hep birlikte başarıyla tamamlanır ya da hiçbiri gerçekleşmez. Yukarıdaki banka transferi örneğinde, para ya her iki hesaptan da düzgün bir şekilde aktarılır ya da aktarılmaz; yarıda kalan bir durum söz konusu olamaz.
  • Consistency (Tutarlılık): Bir işlem başladıktan sonra veritabanı tutarlı bir durumdadır ve işlem bittiğinde de yine tutarlı bir durumdadır. Bu, önceden tanımlanmış tüm kuralların (kısıtlamalar, tetikleyiciler vb.) işlem sonunda geçerli olmaya devam ettiği anlamına gelir.
  • Isolation (İzolasyon): Eşzamanlı olarak yürütülen işlemler birbirini etkilemez. Her işlem, diğer işlemler yokmuş gibi bağımsız olarak yürütülür. Bir işlemin yaptığı değişiklikler, bu işlem tamamen commit edilene kadar diğer işlemler tarafından görülemez.
  • Durability (Kalıcılık): Bir işlem başarıyla commit edildiğinde, yaptığı değişiklikler kalıcıdır ve sistem çökse bile kaybolmaz. Bu, genellikle veritabanının işlem günlüklerine (transaction logs) yazma ve diskte kalıcı hale getirme ile sağlanır.

Bu özellikler sayesinde, veritabanlarımız güvenilir bir şekilde çalışır. Özellikle çok kullanıcılı ortamlarda, eşzamanlılığın yönetilmesi kritik bir konudur. SQL Server, MySQL, PostgreSQL gibi tüm modern ilişkisel veritabanları, bu ACID özelliklerini destekler. Bir işlemi manuel olarak başlatmak için BEGIN TRANSACTION komutunu kullanırız. İşlem başarılı olduğunda COMMIT ile değişiklikleri kalıcı hale getiririz. Eğer bir hata oluşursa veya işlem geri alınmak istenirse, ROLLBACK komutu ile tüm değişiklikler iptal edilir ve veritabanı işlemin başlangıçtaki durumuna döner.

Şimdi bir örnekle daha netleştirelim. Diyelim ki bir e-ticaret siteniz var ve müşteri ürün satın alıyor. Bu süreçte iki temel adım vardır: ürün stoğunu azaltmak ve müşterinin bakiyesinden parayı çekmek. Bu iki adımın aynı anda başarılı olması gerekir. İşte bir SQL örneği:


BEGIN TRANSACTION;
DECLARE @urunID INT = 123;
DECLARE @musteriID INT = 456;
DECLARE @miktar DECIMAL(10, 2) = 50.00;

-- 1. Ürün stoğunu azalt
UPDATE Urunler
SET StokAdedi = StokAdedi - 1
WHERE UrunID = @urunID AND StokAdedi > 0;

IF @@ROWCOUNT = 0
BEGIN
    -- Stok yetersizse işlemi geri al
    ROLLBACK TRANSACTION;
    PRINT 'Stok Yetersiz! İşlem Geri Alındı.';
    RETURN;
END

-- 2. Müşteri bakiyesinden parayı çek
UPDATE MusteriBakiyeleri
SET Bakiye = Bakiye - @miktar
WHERE MusteriID = @musteriID AND Bakiye >= @miktar;

IF @@ROWCOUNT = 0
BEGIN
    -- Bakiye yetersizse işlemi geri al
    ROLLBACK TRANSACTION;
    PRINT 'Bakiye Yetersiz! İşlem Geri Alındı.';
    RETURN;
END

-- Her şey yolundaysa işlemi kalıcı hale getir
COMMIT TRANSACTION;
PRINT 'Satış İşlemi Başarılı!';

Bu örnekte, stok veya bakiye yetersizse tüm işlem geri alınır, böylece veritabanında tutarsız bir durum oluşması engellenir. İşlemlerin bu gücü, uygulamalarımızın güvenle çalışmasını sağlar. Ancak, eşzamanlılığın yönetilmesi konusunda işler bazen karışabilir ve kilitlenmeler gibi sorunlara yol açabilir.

SQL'de Kilitlenmeler (Deadlocks) Nasıl Ortaya Çıkar ve Nasıl Tespit Edilir?

Eşzamanlı işlemlerin veritabanı kaynaklarına aynı anda erişmeye çalışması durumunda kilitlenmeler (deadlocks) meydana gelebilir. Bir kilitlenme, iki veya daha fazla işlemin birbirlerinin sahip olduğu kaynakları beklediği ve sonsuz bir döngüye girdiği bir durumu ifade eder. Bu durum, hiçbir işlemin ilerleyemediği ve veritabanı sisteminin tıkanmasına neden olabileceği anlamına gelir. Genellikle modern veritabanı sistemleri, kilitlenmeleri otomatik olarak algılar ve bunlardan birini "kurban" seçerek sonlandırır (rollback yapar), böylece diğer işlemlerin devam etmesini sağlar. Ancak, bir işlemin geri alınması, uygulama tarafında hataya ve tekrar deneme ihtiyacına neden olur, bu da kullanıcı deneyimini olumsuz etkileyebilir.

Bir Kilitlenme Senaryosu Nasıl Gelişir?

En basit kilitlenme senaryosu, iki işlem (Transaction A ve Transaction B) ve iki kaynak (Resource 1 ve Resource 2) arasında yaşanır. Adım adım inceleyelim:

  1. Transaction A: Resource 1 üzerinde bir kilit (lock) talep eder ve başarılı olur.
  2. Transaction B: Resource 2 üzerinde bir kilit talep eder ve başarılı olur.
  3. Transaction A: Şimdi Resource 2 üzerinde bir kilit talep eder. Ancak Resource 2, Transaction B tarafından kilitlenmiş durumdadır. Transaction A, Transaction B'nin Resource 2 kilidini serbest bırakmasını bekler.
  4. Transaction B: Şimdi Resource 1 üzerinde bir kilit talep eder. Ancak Resource 1, Transaction A tarafından kilitlenmiş durumdadır. Transaction B, Transaction A'nın Resource 1 kilidini serbest bırakmasını bekler.

İşte bu noktada kilitlenme oluşmuştur. Transaction A, Transaction B'nin bitmesini beklerken, Transaction B de Transaction A'nın bitmesini beklemektedir. Her iki işlem de diğerinin serbest bırakmasını beklediği için sonsuza kadar bu durumda kalacaktır. Veritabanı yönetim sistemi (DBMS) bu durumu algılar ve genellikle daha az maliyetli olan bir işlemi "deadlock victim" olarak seçer ve onu geri alır. Bu, diğer işlemin ilerlemesine olanak tanır.

Gerçek Dünya Vaka Analizi: Online Bankacılık

Bir online bankacılık sisteminde, iki farklı kullanıcının aynı anda birbirine para transferi yapmaya çalıştığını düşünelim:

  • Kullanıcı 1 (İşlem A): Kendi hesabından (Hesap X) Kullanıcı 2'nin hesabına (Hesap Y) para göndermek istiyor.
  • Kullanıcı 2 (İşlem B): Kendi hesabından (Hesap Y) Kullanıcı 1'in hesabına (Hesap X) para göndermek istiyor.

Olası kilitlenme adımları:

  1. İşlem A, Hesap X'i güncellerken kilitler.
  2. İşlem B, Hesap Y'yi güncellerken kilitler.
  3. İşlem A, Hesap Y'yi güncellemek ister, ancak Hesap Y, İşlem B tarafından kilitlidir. İşlem A beklemeye başlar.
  4. İşlem B, Hesap X'i güncellemek ister, ancak Hesap X, İşlem A tarafından kilitlidir. İşlem B beklemeye başlar.

Bu senaryo, tipik bir kilitlenme durumunu gösterir. Her iki işlem de birbirlerinin sahip olduğu kaynağı beklediği için ilerleyemezler. Veritabanı sistemi birini geri alarak bu döngüyü kırar. Bu durum, kullanıcılardan birinin işleminin başarısız olduğu anlamına gelir ve tekrar denemesi gerekir.

Kilitlenmeleri Nasıl Tespit Ederiz?

Kilitlenmelerin tespiti ve analizi, performansı ve kullanıcı deneyimini iyileştirmek için hayati öneme sahiptir. Veritabanı sistemleri genellikle kilitlenmeleri algıladığında kendi hata günlüklerine (error logs) bilgi yazar. SQL Server gibi sistemlerde, sp_who2, sys.dm_tran_locks veya sys.dm_os_waiting_tasks gibi dinamik yönetim görünümleri (DMV'ler) kullanarak mevcut kilitleri ve bekleyen görevleri inceleyebiliriz. Ayrıca, SQL Server Profiler veya Extended Events gibi araçlar, kilitlenme olaylarını gerçek zamanlı olarak izlemek ve detaylı kilitlenme grafikleri oluşturmak için kullanılabilir.

Örneğin, mevcut kilitlenmeleri ve bekleyen kaynakları görmek için aşağıdaki gibi sorgular kullanabiliriz:


-- Mevcut kilitleri gösterir
SELECT
    request_session_id,
    resource_type,
    resource_database_id,
    resource_associated_entity_id,
    request_mode,
    request_status,
    request_owner_type,
    resource_description
FROM
    sys.dm_tran_locks
WHERE
    request_status = 'WAIT';

-- Hangi SPID'lerin hangi kilitlerde beklediğini gösterir (SQL Server örneği)
SELECT
    t1.resource_type,
    t1.resource_database_id,
    t1.resource_associated_entity_id,
    t1.request_mode,
    t1.request_session_id,
    t2.blocking_session_id,
    t2.wait_type,
    t2.wait_duration_ms
FROM
    sys.dm_tran_locks as t1
INNER JOIN sys.dm_os_waiting_tasks as t2
    ON t1.request_session_id = t2.session_id;

Bu sorgular, hangi oturumların hangi kaynakları kilitlediğini ve hangi oturumların kilitli kaynaklar üzerinde beklediğini anlamamıza yardımcı olur. Kilitlenme sorunlarını gidermenin ilk adımı, bu sorunların nerede ve neden ortaya çıktığını doğru bir şekilde teşhis etmektir. Bir sonraki bölümde, kilitlenmeleri önlemek veya etkilerini azaltmak için uygulayabileceğimiz stratejileri keşfedeceğiz.

Kilitlenmelerle Başa Çıkma Stratejileri: Performans ve Güvenilirlik İçin Ne Yapmalıyız?

Kilitlenmelerin veritabanı performansı ve uygulama güvenilirliği üzerindeki olumsuz etkilerini en aza indirmek için çeşitli stratejiler mevcuttur. Bu stratejiler, hem veritabanı tasarımı hem de uygulama kodlaması aşamasında dikkate alınmalıdır. Amacımız, kilitlenmeleri tamamen ortadan kaldırmak mümkün olmasa bile, oluşma sıklığını ve etkisini minimize etmektir.

Kilitlenmeleri Önleme ve Azaltma Yöntemleri Nelerdir?

  1. Kaynaklara Her Zaman Aynı Sırayla Erişin: Bu, kilitlenmeleri önlemenin en etkili yollarından biridir. Eğer tüm işlemler, birden fazla kaynak üzerinde kilit talep ederken her zaman aynı sırayı takip ederse, döngüsel bir bekleme durumu oluşma olasılığı önemli ölçüde azalır. Örneğin, eğer işlemler her zaman önce 'Hesaplar' tablosunu, sonra 'Hareketler' tablosunu kilitlerse, bir işlem 'Hareketler' tablosunu kilitli tutarken 'Hesaplar' tablosunu bekleyemez.
  2. İşlemleri Mümkün Olduğunca Kısa ve Etkili Tutun: Uzun süreli işlemler, kaynakları daha uzun süre kilitli tutarak kilitlenme olasılığını artırır. İşlemleri atomik tutmaya özen gösterin; yani sadece gerçekten bir işlem biriminin parçası olan adımları dahil edin. Gereksiz sorguları veya kullanıcıdan uzun süre beklenen girdileri işlem içine dahil etmekten kaçının.
  3. İndeksleri Doğru Kullanın: İyi tasarlanmış indeksler, sorguların daha hızlı çalışmasını sağlar ve bu da kilitlerin daha kısa süre tutulmasına yardımcı olur. Bir sorgu, veritabanında çok fazla veri taramak zorunda kaldığında, daha geniş bir alanı kilitler ve bu kilitleri daha uzun süre tutar. Uygun indeksler, sadece ilgili verilere odaklanılmasını sağlayarak kilit kapsamını daraltır.
  4. İzolasyon Seviyelerini Anlayın ve Akıllıca Kullanın: Veritabanı izolasyon seviyeleri (READ COMMITTED, REPEATABLE READ, SERIALIZABLE gibi), işlemlerin birbirlerinin değişikliklerini ne ölçüde görebileceğini belirler. Daha yüksek izolasyon seviyeleri (örn. SERIALIZABLE), daha fazla veri tutarlılığı sağlarken, eşzamanlılığı azaltır ve kilitlenme olasılığını artırır. Uygulamanızın gereksinimlerine göre en düşük uygun izolasyon seviyesini kullanmak, kilitlenme riskini azaltabilir. Genellikle varsayılan READ COMMITTED çoğu durum için iyi bir dengedir.
  5. Kaynak Taleplerini Azaltın: Tek bir işlemde çok fazla kaynağı kilitlemek yerine, iş yükünü daha küçük, bağımsız işlemlere bölmeyi düşünün. Örneğin, bir toplu güncelleme işlemi, tüm tabloyu kilitlemek yerine, daha küçük veri kümeleri üzerinde çalışacak şekilde parçalara ayrılabilir.

Uzman İpucu: Birçok veritabanı, WITH (NOLOCK) veya READ UNCOMMITTED izolasyon seviyesi gibi seçenekler sunar. Bunlar, okuma işlemlerinin kilitleri atlamasını ve kilitlenme riskini azaltmasını sağlayabilir. Ancak, bu seçenekler "kirli okumalara" (uncommitted data reading) yol açabileceğinden, yalnızca veri tutarlılığının en kritik olmadığı durumlarda dikkatli kullanılmalıdır.

Uygulama Katmanında Yeniden Deneme (Retry Logic) Mantığı Nasıl Uygulanır?

Kilitlenmeler tamamen önlenemese de, meydana geldiklerinde uygulama tarafında bunu ele almanın yolları vardır. En yaygın stratejilerden biri, kilitlenme hatası alan işlemleri otomatik olarak yeniden denemektir. Veritabanı, bir işlemi kilitlenme kurbanı seçip geri aldığında, uygulamaya genellikle belirli bir hata kodu (örneğin, SQL Server'da 1205) döndürür. Uygulama bu hata kodunu yakaladığında, kısa bir bekleme süresinden sonra işlemi tekrar denemeli, ancak belirli bir sayıda deneme başarısız olursa kullanıcıya hata mesajı vermelidir.

Bu yeniden deneme mantığı, özellikle yoğun sistemlerde kullanıcı deneyimini önemli ölçüde iyileştirir çünkü kullanıcı, küçük, geçici bir kilitlenme nedeniyle işleminin hemen başarısız olduğunu görmez. Yeniden denemeler arasında hafif bir rastgele gecikme (exponential backoff) eklemek, aynı anda tekrar kilitlenme yaşama olasılığını azaltabilir.


// C# örneği (pseudocode)
public void TransferPara(int kaynakHesapId, int hedefHesapId, decimal miktar)
{
    int denemeSayisi = 0;
    int maxDeneme = 5;
    bool basarili = false;

    while (denemeSayisi < maxDeneme && !basarili)
    {
        try
        {
            using (var connection = new SqlConnection(connectionString))
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    // SQL Komutları: Kaynak hesaptan düş, hedef hesaba ekle
                    // Örneğin:
                    // new SqlCommand("UPDATE Hesaplar SET Bakiye = Bakiye - @miktar WHERE HesapID = @kaynakHesapId", connection, transaction).ExecuteNonQuery();
                    // new SqlCommand("UPDATE Hesaplar SET Bakiye = Bakiye + @miktar WHERE HesapID = @hedefHesapId", connection, transaction).ExecuteNonQuery();

                    transaction.Commit();
                    basarili = true;
                    Console.WriteLine("İşlem başarıyla tamamlandı.");
                }
            }
        }
        catch (SqlException ex)
        {
            // Kilitlenme hatası (SQL Server'da 1205)
            if (ex.Number == 1205)
            {
                denemeSayisi++;
                Console.WriteLine($"Kilitlenme tespit edildi, yeniden deniyor... ({denemeSayisi}/{maxDeneme})");
                // Rastgele bir süre bekle (exponential backoff)
                Thread.Sleep(TimeSpan.FromMilliseconds(50 * Math.Pow(2, denemeSayisi)));
            }
            else
            {
                Console.WriteLine($"Bir hata oluştu: {ex.Message}");
                throw; // Diğer hataları yeniden fırlat
            }
        }
    }

    if (!basarili)
    {
        Console.WriteLine("İşlem defalarca başarısız oldu, lütfen daha sonra tekrar deneyin.");
    }
}

Bu uygulama tarafı yaklaşımı, veritabanı katmanındaki kilitlenmeleri tamamen engellemese de, kullanıcıların bu durumdan en az etkilenmesini sağlayarak sistemin genel kullanılabilirliğini ve performansını artırır. Sonuç olarak, kilitlenmelerle başa çıkmak, hem dikkatli veritabanı tasarımı hem de dayanıklı uygulama mimarisi gerektiren çok yönlü bir çabadır.

Günlük Tabanlı Kurtarma (Log-Based Recovery) Nedir ve Veri Bütünlüğünü Nasıl Sağlar?

Veritabanı sistemlerinin temel hedeflerinden biri, herhangi bir felaket (sistem çökmesi, elektrik kesintisi, donanım arızası vb.) durumunda bile veri bütünlüğünü ve kalıcılığını garanti etmektir. İşte bu noktada günlük tabanlı kurtarma (log-based recovery) mekanizmaları devreye girer. Bu sistemler, veritabanında yapılan her değişikliği (insert, update, delete) detaylı bir şekilde bir işlem günlüğüne (transaction log) kaydeder. Bu kayıtlar, veritabanı çökse bile, sistemin son tutarlı durumuna geri dönebilmesini sağlar.

Write-Ahead Logging (WAL) Prensibi Nedir?

Günlük tabanlı kurtarmanın merkezinde, Write-Ahead Logging (WAL) prensibi yatar. WAL, herhangi bir veritabanı sayfasındaki bir değişiklik diskteki ana veri dosyasına yazılmadan önce, bu değişikliğin açıklamasını içeren günlük kaydının (log record) diske yazılmasını zorunlu kılar. Bu prensip, veritabanı kurtarmanın en önemli garantisidir. Eğer sistem bir anda çökerse ve bazı değişiklikler henüz ana veri dosyasına yazılmamışsa, günlük dosyası sayesinde bu değişiklikler yeniden uygulanabilir (REDO) veya kısmen yapılmış işlemler geri alınabilir (UNDO).

Her bir günlük kaydı tipik olarak aşağıdaki bilgileri içerir:

  • İşlem Kimliği (Transaction ID): Hangi işlemin bu değişikliği yaptığını belirtir.
  • Değişiklik Tipi: INSERT, UPDATE, DELETE gibi.
  • Değiştirilen Veri Sayfası: Hangi veri sayfasının etkilendiğini belirtir.
  • Eski Değer (Old Value): Değişiklik öncesindeki verinin değeri.
  • Yeni Değer (New Value): Değişiklik sonrası verinin değeri.
  • İşlem Sonrası Durumu (LSN - Log Sequence Number): Günlük dosyasındaki kaydın benzersiz sırası.

Bu detaylı kayıtlar sayesinde, veritabanı motoru herhangi bir anda veritabanının hangi durumda olduğunu tam olarak bilebilir ve gerektiğinde tutarlı bir duruma geri dönebilir.

Checkpoints ve Kurtarma Süreci: REDO ve UNDO İşlemleri

Günlük dosyaları sürekli büyüdüğü için, veritabanı motoru belirli aralıklarla "checkpoint" adı verilen bir işlem yapar. Bir checkpoint, o ana kadar bellekteki tüm kirli sayfaları (yani diskteki versiyonundan farklı olan sayfaları) diske yazılmaya zorlar ve bu durumu günlük dosyasında işaretler. Checkpointler, kurtarma süresini önemli ölçüde kısaltır çünkü sistem çöktüğünde, kurtarma işlemi son checkpoint'ten başlamak zorunda kalır, günlük dosyasının başından değil. Bu, uzun süreli bir kurtarma işlemi yerine daha hızlı bir geri dönüş sağlar.

Bir sistem çökmesi sonrası veritabanı başlatıldığında, kurtarma süreci genellikle üç aşamadan oluşur:

  1. Analysis (Analiz): Veritabanı, günlük dosyasını en son checkpoint'ten itibaren tarar ve hangi işlemlerin başladığını, hangilerinin commit edildiğini ve hangilerinin hala aktif olduğunu belirler. Bu aşamada, hangi işlemlerin REDO edilmesi, hangilerinin UNDO edilmesi gerektiği listelenir.
  2. REDO (Yeniden Uygulama): Checkpoint'ten sonra commit edilmiş ancak henüz veri dosyalarına yazılmamış tüm değişiklikler, günlük dosyasındaki bilgiler kullanılarak veritabanına yeniden uygulanır. Bu, kalıcılık (durability) özelliğinin sağlanması için hayati önem taşır.
  3. UNDO (Geri Alma): Çökme anında hala aktif olan veya commit edilmemiş tüm işlemler, günlük dosyasındaki "eski değerler" kullanılarak geri alınır. Bu, atomiklik (atomicity) ve tutarlılık (consistency) özelliklerinin sağlanmasına yardımcı olur.

Bu süreç, veritabanının çökme öncesindeki tutarlı durumuna geri dönmesini ve hiçbir onaylanmış verinin kaybolmamasını sağlar. Günlük tabanlı kurtarma, modern veritabanı sistemlerinin neden bu kadar güvenilir olduğunun temel nedenidir. Bu mekanizma olmasaydı, her sistem çökmesi potansiyel bir veri felaketi anlamına gelirdi. Bu günlük dosyaları aynı zamanda yedekleme ve felaket kurtarma stratejilerinde de merkezi bir rol oynar.

Veritabanı Kurtarma Modelleri: İhtiyaçlarınıza En Uygun Seçim Nasıl Yapılır?

Veritabanı kurtarma modelleri, veritabanınızın yedeklenmesi ve bir felaket durumunda kurtarılması için nasıl davranacağını belirler. Özellikle SQL Server gibi sistemlerde, farklı kurtarma modelleri, veri kaybı toleransı ve yedekleme esnekliği açısından farklı seçenekler sunar. Doğru kurtarma modelini seçmek, işletmenizin veri bütünlüğü gereksinimleri ve kurtarma zamanı hedefleri (RTO - Recovery Time Objective, RPO - Recovery Point Objective) ile doğrudan ilişkilidir.

FULL, SIMPLE ve BULK_LOGGED Kurtarma Modelleri Arasındaki Farklar

SQL Server özelinde üç ana kurtarma modeli bulunur:

  1. FULL Recovery Model (Tam Kurtarma Modeli):
    • Ne yapar: Tüm işlem günlüklerini eksiksiz olarak kaydeder. Bu modelde, veri değişiklikleri ve işlem günlükleri birbirine bağımlıdır.
    • Avantajları: Herhangi bir noktaya (point-in-time) kurtarma yapma olanağı sunar. Bu, belirli bir zamana kadar veri kaybını en aza indirmek için en esnek seçenektir. Felaket durumunda, son yedekten ve ardından gelen tüm işlem günlüğü yedeklerinden faydalanarak veritabanınızı çökme anına kadar kurtarabilirsiniz.
    • Dezavantajları: İşlem günlüğü dosyaları zamanla büyüyebilir ve düzenli olarak işlem günlüğü yedeklerinin alınmasını ve küçültülmesini gerektirir. Bu, daha fazla yönetim yükü ve depolama alanı gerektirir.
    • Kimler için: Veri kaybına toleransın sıfıra yakın olduğu, kritik iş uygulamaları (bankacılık, e-ticaret, finans sistemleri) için idealdir.
  2. SIMPLE Recovery Model (Basit Kurtarma Modeli):
    • Ne yapar: İşlem günlüğü, bir checkpoint gerçekleştiğinde otomatik olarak küçülür (truncate edilir). Yalnızca en son checkpoint'e kadar olan bilgileri tutar.
    • Avantajları: İşlem günlüğü yönetimi gereksizdir, otomatik olarak küçültüldüğü için depolama alanı konusunda daha az endişe duyulur. Daha az yönetim yükü vardır.
    • Dezavantajları: Sadece en son tam veya diferansiyel yedeğe kadar kurtarma yapılabilir. Veritabanının çökmesi durumunda, son yedekten bu yana yapılan tüm değişiklikler kaybolur. Nokta kurtarma (point-in-time recovery) mümkün değildir.
    • Kimler için: Test ve geliştirme veritabanları veya veri kaybının kabul edilebilir olduğu, daha az kritik uygulamalar için uygundur.
  3. BULK_LOGGED Recovery Model (Toplu Kayıt Kurtarma Modeli):
    • Ne yapar: FULL modeline benzer, ancak bazı büyük veri işlemleri (örneğin, BULK INSERT, SELECT INTO, indeks yeniden oluşturma) için günlük kaydını minimuma indirir (minimally logged).
    • Avantajları: FULL modelinin birçok avantajını sunarken, belirli toplu işlemler sırasında disk G/Ç yükünü ve işlem günlüğü boyutunu azaltır. Daha hızlı toplu veri yüklemeleri sağlar.
    • Dezavantajları: Toplu işlemler sırasında oluşacak bir çökmede, nokta kurtarma (point-in-time recovery) toplu işlemin tamamlanmasından önceki son işlem günlüğü yedeğine kadar mümkündür. Toplu işlemin yapıldığı sürece nokta kurtarma imkanı kısmen kaybedilir.
    • Kimler için: Büyük veri yüklemeleri veya indeks bakımı yapılan ancak yine de veri kaybını en aza indirmek isteyen sistemler için bir ara çözüm sunar.

Uzman İpucu: Kurtarma modeli seçimi, uygulamanızın RPO (Recovery Point Objective - ne kadar veri kaybına dayanabileceğiniz) ve RTO (Recovery Time Objective - veritabanını ne kadar sürede çalışır hale getirebileceğiniz) hedeflerine göre yapılmalıdır. Kritik iş yükleri için genellikle FULL kurtarma modeli tercih edilir.

Yedekleme Stratejileri ve Felaket Kurtarma Senaryoları

Kurtarma modelleriyle birlikte, etkili bir yedekleme stratejisi de oluşturmanız gerekir:

  • Tam (Full) Yedeklemeler: Veritabanının tamamının bir kopyasıdır. Tüm veriyi ve günlük dosyasının bir kısmını içerir.
  • Diferansiyel (Differential) Yedeklemeler: Son tam yedeklemeden bu yana değişen tüm verileri içerir. Daha küçük boyutludur ve daha hızlı alınır. Kurtarma için en son tam yedeğe ve en son diferansiyel yedeğe ihtiyaç duyar.
  • İşlem Günlüğü (Transaction Log) Yedeklemeleri: Yalnızca FULL veya BULK_LOGGED kurtarma modelinde mümkündür. Son işlem günlüğü yedeğinden bu yana oluşan tüm günlük kayıtlarını içerir. Nokta kurtarma için vazgeçilmezdir.

Bir felaket kurtarma senaryosunda, veritabanını yeniden kurmak için önce en son tam yedekten, ardından varsa en son diferansiyel yedekten ve son olarak da çökme anına kadar olan tüm ardışık işlem günlüğü yedeklerinden faydalanılır. İşte bir RESTORE DATABASE komutu örneği:


-- Tam yedeği geri yükle (NO_RECOVERY ile, çünkü daha fazla günlük uygulanacak)
RESTORE DATABASE YourDatabaseName
FROM DISK = 'C:\Backup\YourDatabaseName_Full.bak'
WITH NORECOVERY, REPLACE;

-- Diferansiyel yedeği geri yükle (eğer varsa, yine NO_RECOVERY ile)
-- RESTORE DATABASE YourDatabaseName
-- FROM DISK = 'C:\Backup\YourDatabaseName_Diff.bak'
-- WITH NORECOVERY;

-- İşlem günlüğü yedeklerini sırayla uygula
RESTORE LOG YourDatabaseName
FROM DISK = 'C:\Backup\YourDatabaseName_Log1.trn'
WITH NORECOVERY;

RESTORE LOG YourDatabaseName
FROM DISK = 'C:\Backup\YourDatabaseName_Log2.trn'
WITH NORECOVERY;

-- Son işlem günlüğü yedeğini ve kurtarma işlemini tamamla
-- (Burada TO_DATE veya STOPAT seçenekleri ile nokta kurtarma yapılabilir)
RESTORE LOG YourDatabaseName
FROM DISK = 'C:\Backup\YourDatabaseName_Log_Last.trn'
WITH RECOVERY; -- Bu, veritabanını online hale getirir

Bu adımlar, veritabanınızı felaketten kurtarmanın temelini oluşturur. Düzenli test yedeklemeleri ve kurtarma senaryoları, bu sürecin sorunsuz çalışmasını sağlamak için kritik öneme sahiptir. Veritabanı yöneticilerinin en önemli sorumluluklarından biri, uygun kurtarma modelini seçmek ve belirlenen RPO/RTO hedeflerini karşılayacak sağlam bir yedekleme ve kurtarma stratejisi uygulamaktır.

Sonuç ve Sıkça Sorulan Sorular

Bu makalede, SQL veritabanı dünyasının temel direklerinden olan işlemler, kilitlenmeler ve günlük tabanlı kurtarma mekanizmalarını detaylı bir şekilde inceledik. Gördüğümüz gibi, veritabanı işlemleri, ACID özellikleriyle veri bütünlüğünün ve tutarlılığının garantörüdür. Kilitlenmeler ise eşzamanlılığın kaçınılmaz bir yan etkisi olup, doğru stratejilerle yönetilmesi gereken performans engelleridir. Son olarak, günlük tabanlı kurtarma ve farklı kurtarma modelleri sayesinde, en kötü senaryolarda bile veritabanı sistemlerimizin veriyi koruyabildiğini ve işletmelerin hızlıca toparlanabildiğini öğrendik. Tüm bu kavramlar, sağlam, güvenilir ve yüksek performanslı veritabanı uygulamaları geliştirmek ve yönetmek için temel bilgilerdir.

Veritabanı yöneticileri ve geliştiriciler olarak, bu mekanizmaların derinlemesine anlaşılması, sadece sorunları çözmekle kalmaz, aynı zamanda gelecekteki olası sorunları önceden tahmin etme ve daha dayanıklı sistemler tasarlama yeteneğimizi de artırır. Unutmayın, iyi bir veritabanı yönetimi, projenin başarısı için vazgeçilmezdir.

Sıkça Sorulan Sorular

SQL'de en yaygın kilitlenme türü nedir?
En yaygın kilitlenme türü, iki veya daha fazla işlemin, birbirlerinin tuttuğu kaynakları karşılıklı olarak beklediği "döngüsel bekleme" (circular wait) kilitlenmeleridir. Genellikle UPDATE veya DELETE işlemleri sırasında tablolar veya satırlar üzerinde tutulan kilitler nedeniyle oluşurlar.
READ COMMITTED izolasyon seviyesi kilitlenmeleri önler mi?
READ COMMITTED izolasyon seviyesi, okunmamış verilerin okunmasını engeller ve diğer işlemlerin commit edilmemiş değişikliklerini görmemeyi sağlar. Ancak, özellikle yazma kilitleriyle ilgili olan kilitlenmeleri doğrudan önlemez. Kilitlenmeleri azaltmak için diğer stratejiler (işlem sürelerini kısaltma, kaynaklara sıralı erişim vb.) gereklidir.
Veritabanı çöktüğünde FULL kurtarma modeli ne kadar veri kaybına izin verir?
FULL kurtarma modeli, düzgün bir yedekleme stratejisi (tam yedeklemeler ve düzenli işlem günlüğü yedeklemeleri) uygulandığında, çökme anına kadar olan tüm verilerin kurtarılmasına olanak tanır. Teorik olarak, doğru bir şekilde uygulandığında veri kaybı sıfıra yakındır (yalnızca son günlük yedeği ile çökme anı arasındaki çok küçük bir zaman dilimi etkilenebilir, ancak genellikle bu da kurtarılabilir).
Transaction log dosyası neden sürekli büyüyor ve ne yapmalıyım?
Transaction log dosyası, FULL veya BULK_LOGGED kurtarma modelindeyseniz ve düzenli işlem günlüğü yedeklemeleri almıyorsanız büyür. Günlük yedekleri, günlük dosyasındaki etkin olmayan (artık kurtarma için gerekli olmayan) kısımların kesilmesini (truncate edilmesini) sağlar. Çözüm, düzenli ve sık aralıklarla (iş yükünüze göre değişmekle birlikte genellikle her 15-30 dakikada bir) işlem günlüğü yedeklemeleri almaktır. Eğer hala büyüyorsa, uzun süreli açık işlemler veya yedekleme zincirinde bir sorun olabilir.
Uygulama katmanında kilitlenme hatasını nasıl yakalamalıyım?
Çoğu veritabanı API'si (örn. .NET'te SqlConnection, Java'da JDBC), veritabanından dönen hataları yakalamak için özel istisnalar veya hata kodları sunar. SQL Server için, SqlException sınıfının Number özelliğini kontrol ederek kilitlenme hata kodu olan 1205'i yakalayabilirsiniz. Diğer veritabanları için ilgili dökümanları inceleyerek kendi spesifik kilitlenme hata kodlarını bulmanız gerekir. Hata yakalandığında, işlemi geri alıp (rollback) uygun bir gecikmeyle yeniden deneme mekanizması uygulamak en iyi yaklaşımdır.

Mobil Uyumlu HTML için Örnek Media Query

Modern web sitelerinin mobil cihazlarda da düzgün görünmesi hayati öneme sahiptir. Aşağıdaki CSS kodu örneği, bir sayfanın düzeninin farklı ekran boyutlarına nasıl uyarlanabileceğini göstermektedir. Bu makalenin içeriği de bu prensiplere uygun olarak tasarlanmıştır.




Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

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

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.