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.
-- 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ürNe 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.
-- 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#### T-SQL ile SCD Type 2 MERGE
Forumda en çok istenen kod: MERGE ile SCD Type 2 implementasyonu.
-- 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)
);SCD Type 3: Yeni Kolon (Limited History)
Yalnızca mevcut ve önceki değeri tutar. Sınırlı geçmiş.
-- 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.
Fabric / Lakehouse'da SCD
Microsoft Fabric'te SCD uygulamak için Delta Lake'in time travel özelliğinden yararlanabilirsiniz:
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.
