SCD Nedir ve Neden Herkes Soruyor?

Veri ambarı forumlarında en sık sorulan sorulardan biri: _"Müşteri adres değiştirdiğinde geçmiş raporlarım nasıl etkilenir?"_ Cevap: Slowly Changing Dimensions (SCD) konseptinde gizli.

Dimension tablolarındaki veriler zamanla değişir — müşteri taşınır, ürün kategorisi değiştirilir, çalışan terfi eder. Bu değişiklikleri veri ambarında nasıl yönettiğiniz, raporlarınızın doğruluğunu belirler.

SCD Tipleri

SCD Type 1: Üstüne Yaz (Overwrite)

En basit yaklaşım. Değişen veri doğrudan güncellenir, geçmiş kaybolur.

SQL
-- SCD Type 1: Basit UPDATE
UPDATE DimMusteri
SET Sehir = 'Ankara', GuncellemeTarihi = GETDATE()
WHERE MusteriID = 1001;

-- Sonuç: Müşterinin eski şehri (İstanbul) kaybolur
-- Tüm geçmiş raporlarda Ankara görünür

Ne zaman kullanılır?

  • Yazım hataları düzeltme (İstanbull → İstanbul)
  • Önemsiz alan güncellemeleri (telefon numarası)
  • Geçmişin önemli olmadığı durumlar

SCD Type 2: Yeni Satır (Historical Tracking)

En yaygın ve en çok tartışılan SCD tipi. Her değişiklik yeni bir satır olarak eklenir. Geçmiş tamamen korunur.

SQL
-- SCD Type 2 tablo yapısı
CREATE TABLE DimMusteri (
    MusteriKey INT IDENTITY PRIMARY KEY,  -- Surrogate key
    MusteriID INT,                         -- Business key
    Ad NVARCHAR(100),
    Sehir NVARCHAR(100),
    Segment NVARCHAR(50),
    GecerliBaslangic DATE,
    GecerliBitis DATE,
    AktifMi BIT DEFAULT 1
);

-- Örnek veri:
-- MusteriKey | MusteriID | Sehir    | Baslangic  | Bitis      | Aktif
-- 1          | 1001      | İstanbul | 2020-01-01 | 2024-06-15 | 0
-- 2          | 1001      | Ankara   | 2024-06-15 | 9999-12-31 | 1
SCD Type 2 ETL Akışı
EXTRACTVeri KaynaklarıTRANSFORMTemizle & DönüştürLOADVeri Ambarı

#### T-SQL ile SCD Type 2 MERGE

Forumda en çok istenen kod: MERGE ile SCD Type 2 implementasyonu.

SQL
-- SCD Type 2: MERGE pattern
-- 1. Değişen kayıtları tespit et
-- 2. Eski kaydı kapat (AktifMi = 0, GecerliBitis = bugün)
-- 3. Yeni kaydı ekle (AktifMi = 1, GecerliBitis = 9999-12-31)

MERGE DimMusteri AS hedef
USING Staging_Musteri AS kaynak
    ON hedef.MusteriID = kaynak.MusteriID AND hedef.AktifMi = 1

-- Yeni müşteri: Doğrudan ekle
WHEN NOT MATCHED BY TARGET THEN
    INSERT (MusteriID, Ad, Sehir, Segment, GecerliBaslangic, GecerliBitis, AktifMi)
    VALUES (kaynak.MusteriID, kaynak.Ad, kaynak.Sehir, kaynak.Segment, 
            GETDATE(), '9999-12-31', 1)

-- Değişen müşteri: Eski kaydı kapat
WHEN MATCHED AND (
    hedef.Sehir <> kaynak.Sehir OR
    hedef.Segment <> kaynak.Segment
) THEN
    UPDATE SET 
        hedef.AktifMi = 0,
        hedef.GecerliBitis = GETDATE()

OUTPUT $action, kaynak.*;

-- 3. Değişen müşteriler için yeni satır ekle
INSERT INTO DimMusteri (MusteriID, Ad, Sehir, Segment, GecerliBaslangic, GecerliBitis, AktifMi)
SELECT MusteriID, Ad, Sehir, Segment, GETDATE(), '9999-12-31', 1
FROM Staging_Musteri s
WHERE EXISTS (
    SELECT 1 FROM DimMusteri d 
    WHERE d.MusteriID = s.MusteriID 
    AND d.AktifMi = 0 
    AND CAST(d.GecerliBitis AS DATE) = CAST(GETDATE() AS DATE)
);
⚠️Forum Uyarısı: MERGE statement'ı tek başına SCD Type 2'yi tam karşılayamaz çünkü aynı anda UPDATE ve INSERT yapamaz aynı kayıt için. Yukarıdaki pattern iki aşamalıdır: önce UPDATE, sonra INSERT.

SCD Type 3: Yeni Kolon (Limited History)

Yalnızca mevcut ve önceki değeri tutar. Sınırlı geçmiş.

SQL
-- SCD Type 3 tablo yapısı
ALTER TABLE DimMusteri
ADD OncekiSehir NVARCHAR(100),
    SehirDegisimTarihi DATE;

-- Güncelleme:
UPDATE DimMusteri
SET OncekiSehir = Sehir,
    Sehir = 'Ankara',
    SehirDegisimTarihi = GETDATE()
WHERE MusteriID = 1001;

Karşılaştırma

| Özellik | Type 1 | Type 2 | Type 3 |

|---|---|---|---|

| Geçmiş korunur mu? | ❌ | ✅ Tam | ⚡ Kısmi (son 2) |

| Tablo büyüklüğü | Sabit | Büyür | Sabit |

| Karmaşıklık | Düşük | Yüksek | Orta |

| Kullanım sıklığı | Yaygın | En yaygın | Nadir |

| Surrogate key gerekli mi? | Hayır | Evet | Hayır |

SSIS ile SCD Implementasyonu

SSIS'te yerleşik Slowly Changing Dimension wizard'ı vardır ama forumda herkes şikayet eder — performansı kötü çünkü satır-satır işler.

💡SSIS'in SCD wizard'ı yerine Execute SQL Task içinde MERGE statement kullanın. 10-100 kat daha hızlı.

Fabric / Lakehouse'da SCD

Microsoft Fabric'te SCD uygulamak için Delta Lake'in time travel özelliğinden yararlanabilirsiniz:

Python
class="code-comment"># Fabric Notebook - Delta Lake ile basit SCD
from delta.tables import DeltaTable

delta_musteri = DeltaTable.forPath(spark, class="code-string">"Tables/dim_musteri")

class="code-comment"># MERGE ile upsert (SCD Type class="code-number">1)
delta_musteri.alias(class="code-string">"hedef").merge(
    df_yeni_musteri.alias(class="code-string">"kaynak"),
    class="code-string">"hedef.MusteriID = kaynak.MusteriID"
).whenMatchedUpdateAll(
).whenNotMatchedInsertAll(
).execute()

class="code-comment"># Time travel ile geçmişe bakma
df_gecmis = spark.read.format(class="code-string">"delta").option(class="code-string">"versionAsOf", class="code-number">5).load(class="code-string">"Tables/dim_musteri")

Sonuç

SCD, veri ambarı tasarımının en kritik konularından biridir. Çoğu projede SCD Type 2 en doğru seçimdir — tam geçmiş koruması sağlar ve raporlarda "o zamanki durum"u yansıtır. MERGE pattern'ı ile T-SQL'de verimli şekilde implemente edin, SSIS wizard'ından kaçının. Fabric'te ise Delta Lake'in time travel özelliğini değerlendirin.