---
title: 'Göl Evi Yaklaşımı'
source: 'https://academia.sh/tr/kurslar/veri-depolama-mimarileri/gol-evi-yaklasimi'
course: 'Veri Depolama Mimarileri'
language: tr
updated: '2026-08-17T18:08:51+00:00'
license: 'CC BY-SA 4.0'
---

# Göl Evi Yaklaşımı

Ham katman korunurken şema dayatmasının okuma anına taşınmasının kazandırdığının ve kaybettirdiğinin sayılması: yazma kapısı altı bozulma sınıfının ikisini sıfır aşama gecikmeyle yakalıyor ve dördünü hiç yakalamıyor, hiçbir dayatması olmayan düzenek altısını da yakalamıyor, okuma anında dayatan düzenek altısını da yakalıyor ve ortalama gecikmesi 1,33 aşama oluyor. Ortalamanın yükselmesi kötüleşme değil, tanımsız dört değerin sonlu hâle gelmesidir. Alan adı değişimi altında ham katmanı koruyan düzenek 2200 düzenli satır üretiyor, kapıda eleyen düzenek 200 satırı reddedip 1800'de kalıyor; bedel saklanan hücrenin 12600 yerine 29800 olmasıdır. Birim değişimi hiçbir kapıya takılmadan düzenli katmana yazılıyor ve ancak dördüncü aşamada görülüyor.

Önceki iki ders iki uç kararı ölçtü. Veri ambarı şemayı yazma anında dayatıyor, sorguya 520
maliyetli bir okuma veriyor ve karşılığında kurtarılabilir 400 satırı yok ediyor. Veri gölü hiçbir
satırı yok etmiyor, karşılığında aynı sorguya 14520 ödetiyor ve doğru yorumu tüketiciye bırakıyor;
aynı ham katmanı okuyan iki tüketicinin 48004 ile 58454 metreküp bulması bunun sonucuydu.

**Göl evi (lakehouse)** bu iki kararı ayırıp yeniden birleştirir. Ham katman gölde olduğu gibi
korunur: gelen satır ne ise o yazılır, hiçbir şey reddedilmez. Şema dayatması ortadan kalkmaz, ama
yazma anından alınıp **okuma anına** taşınır ve tek bir yerde toplanır; sonucu ambarınki gibi
şemaya uyumlu ve bölümlenmiş bir **düzenli katmandır**. Bu birleşimin kazandırdığı ve kaybettirdiği
tek bir eksende okunur: **yakalama gecikmesi**. Ölçü Veri Mühendisliğine Giriş kursunun birimiyle,
yani **aşama** olarak yazılır, böylece üç düzenek aynı cetvelle karşılaştırılabilir.

- **DY16.** Kod bir **kurgudur**; hiçbir göl evi ürünü, tablo biçimi, katalog ya da sorgu motoru adı
  yazılmaz. Kaynak, hat ve denetimler Veri Mühendisliğine Giriş kursundan devralınır, tohum
  **20260218**.
- **DY17.** Göl evi iki katmanlıdır: **ham katman** gelen satırı olduğu gibi tutar, **düzenli
  katman** şema dayatılmış hat çıkışını tutar. Dayatma düzenli katman kurulurken, yani **okuma
  anında** koşar.
- **DY18.** Yakalama gecikmesi **aşama** olarak yazılır: **0** hiçbir aşama koşmadan, **1** ile
  **5** beş aşamanın sırası. Süre ham olarak yazılmaz.
- **DY19.** Yedi denetim ve altı bozulma sınıfı Veri Mühendisliğine Giriş kursundan **aynen** alınır
  ve yordamları **tekrarlanmaz**. Bu dersin yeni sorusu tek satırlıktır: dayatma okuma anına
  taşındığında gecikme ne oluyor.
- **DY20.** Ambarın yazma kapısı yalnız **satır kapsamı** görür, yani `sema` ile `tip`; küme ve özet
  kapsamındaki denetimler yazma anında koşamaz. Bu ayrım önceki derste ölçüldü.
- **DY21.** Ham katman korunduğu için **onarım** mümkündür: alan adı eşlemesi ve tür çevrimi. Ambar
  kapısında onarım yoktur; uymayan satır reddedilir.
- **DY22.** Sorgu maliyeti bu derste yeniden ölçülmez, önceki iki dersten **girdi** alınır: ham
  katmanda 14520, `donem` bölümlü düzenli katmanda 520. **Dosya sabiti 120 bir seçimdir.**

## Dayatmayı Okuma Anına Taşımak

Üç düzenek aynı bozuk kaynağı görür ve yalnız **hangi denetimin nerede koştuğu** bakımından
ayrılır. Ambarda yazma kapısı yalnız satır kapsamındaki iki denetimi işletir. Gölde hiçbir denetim
yoktur. Göl evinde yedi denetimin tamamı okuma anında, düzenli katman kurulurken koşar ve her biri
kendi aşamasında ateşler.

```python
# KURGU hat ve denetimler -- gercek bir gol evi urunu, tablo bicimi ya da sorgu
# motoru cagrilmaz. Kaynak bir olcum aginin KURGU sayac okumalaridir, tohum 20260218.
TOHUM, M32 = 20260218, 0xFFFFFFFF


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
DONEM = [f"2026-{a:02d}" for a in range(1, 13)]
ABONE = {}
for i in range(200):
    r = uretec(TOHUM + 37 * i)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "baslangic": 10000 + int(r() * 60000)}


def kaynak_uret():
    kayit = []
    for i, (ab, a) in enumerate(ABONE.items()):
        e = a["baslangic"]
        for d in DONEM:
            r = uretec(TOHUM + 101 * i + 7 * DONEM.index(d))
            e += 4 + int(r() * 46)
            kayit.append({"abone": ab, "donem": d, "bolge": a["bolge"], "tip": a["tip"],
                          "endeks": e, "birim": "m3"})
    return kayit


BOZULMA = ["gec_gelen", "yinelenen", "sema_degisti", "birim_degisti", "eksik_bolum", "kayan_tip"]


def boz(kayit, sinif, donem="2026-07"):
    """Tek bir donemi bozar , kalan donemler saglam kalir."""
    yeni, sayac = [], 0
    for k in kayit:
        if k["donem"] != donem:
            yeni.append(k)
            continue
        if sinif == "gec_gelen":
            if k["abone"] <= "A040":                # bu donemde 40 abone hic gelmedi
                sayac += 1
                continue
            yeni.append(k)
        elif sinif == "yinelenen":
            yeni.append(k)
            if k["abone"] <= "A060":                # 60 kayit iki kez geldi
                yeni.append(dict(k))
                sayac += 1
        elif sinif == "sema_degisti":
            y = dict(k)
            y["endeks_degeri"] = y.pop("endeks")    # alan adi degisti
            sayac += 1
            yeni.append(y)
        elif sinif == "birim_degisti":
            y = dict(k)
            y["endeks"] = k["endeks"] * 1000        # m3 yerine litre
            y["birim"] = "m3"                       # ETIKET DEGISMEDI , sessiz bozulma
            sayac += 1
            yeni.append(y)
        elif sinif == "eksik_bolum":
            if k["bolge"] == "kuzey":               # bir bolgenin bolumu hic yazilmadi
                sayac += 1
                continue
            yeni.append(k)
        elif sinif == "kayan_tip":
            y = dict(k)
            y["endeks"] = str(k["endeks"])          # sayi metne dondu
            sayac += 1
            yeni.append(y)
    return yeni, sayac


def a1_ayikla(kayit):
    ZOR = ("abone", "donem", "bolge", "endeks", "birim")
    tut = [k for k in kayit if all(a in k for a in ZOR)]
    return tut, len(kayit) - len(tut)


def a2_tekille(kayit):
    gor, tut = set(), []
    for k in kayit:
        ad = (k["abone"], k["donem"])
        if ad in gor:
            continue
        gor.add(ad)
        tut.append(k)
    return tut, len(kayit) - len(tut)


def a3_tuketim(kayit):
    """Donem farkindan tuketim. Onceki donem yoksa satir hesaplanamaz."""
    tablo = {(k["abone"], k["donem"]): k for k in kayit}
    cikti, dusen = [], 0
    for k in kayit:
        i = DONEM.index(k["donem"])
        if i == 0:
            continue
        onceki = tablo.get((k["abone"], DONEM[i - 1]))
        if onceki is None:
            dusen += 1
            continue
        try:
            f = int(k["endeks"]) - int(onceki["endeks"])
        except (TypeError, ValueError):
            dusen += 1
            continue
        cikti.append(dict(k, m3=f))
    return cikti, dusen


def a4_ozet(kayit):
    top = {}
    for k in kayit:
        ad = (k["bolge"], k["donem"])
        top[ad] = top.get(ad, 0) + k["m3"]
    return top, 0


def a5_sun(ozet):
    """Sunum: bolge basina donem ortalamasi."""
    bolge = {}
    for (b, d), v in ozet.items():
        bolge.setdefault(b, []).append(v)
    return {b: round(sum(v) / len(v), 2) for b, v in bolge.items()}, 0


ASAMA = [("ayikla", a1_ayikla), ("tekille", a2_tekille), ("tuketim", a3_tuketim),
         ("ozet", a4_ozet), ("sun", a5_sun)]


# ---- DENETIMLER: her biri belirli bir asamadan SONRA kosar
def d_sema(veri, alanlar=("abone", "donem", "bolge", "endeks", "birim")):
    return any(any(a not in k for a in alanlar) for k in veri)


def d_tip(veri):
    return any(not isinstance(k.get("endeks"), int) for k in veri)


def d_tekillik(veri):
    ad = [(k["abone"], k["donem"]) for k in veri]
    return len(ad) != len(set(ad))


def d_satir_sayisi(veri, beklenen, pay=0.05):
    return abs(len(veri) - beklenen) / beklenen > pay


def d_bolum_tamligi(veri):
    """KUSURLU DENETIM: bolge kumesine bakar , donemi gormez."""
    return set(k["bolge"] for k in veri) != set(BOLGE)


def d_bolum_tamligi_donem(veri):
    """DOGRU DENETIM: her donemde her bolge var mi."""
    gor = set((k["bolge"], k["donem"]) for k in veri)
    return gor != set((b, d) for b in BOLGE for d in DONEM)


def d_dagilim(ozet, taban, pay=0.25):
    for ad, v in ozet.items():
        t = taban.get(ad)
        if t and abs(v - t) / max(abs(t), 1) > pay:
            return True
    return False


DENETIM = [
    ("sema", 0, lambda v, t: d_sema(v)),
    ("tip", 0, lambda v, t: d_tip(v)),
    ("tekillik", 0, lambda v, t: d_tekillik(v)),
    ("satir_sayisi", 0, lambda v, t: d_satir_sayisi(v, t["beklenen_satir"])),
    ("bolum", 0, lambda v, t: d_bolum_tamligi(v)),
    ("bolum_donem", 0, lambda v, t: d_bolum_tamligi_donem(v)),
    ("dagilim", 4, lambda v, t: d_dagilim(v, t["taban_ozet"])),
]


def denetimli_hat(kayit, taban, acik=None):
    """Hatti kosturur ve her asamadan sonra acik denetimleri isletir.
    Donen deger: sunum , iz , ilk yakalayan denetim ve yakalama gecikmesi (asama)."""
    acik = [a for a, _, _ in DENETIM] if acik is None else acik
    veri, iz, yakalayan, gecikme = kayit, [], None, None
    for adim in range(len(ASAMA) + 1):
        if adim > 0:
            ad, f = ASAMA[adim - 1]
            veri, dusen = f(veri)
            iz.append({"asama": ad, "kalan": len(veri), "dusen": dusen})
        for dad, dasama, df in DENETIM:
            if dad not in acik or dasama != adim:
                continue
            if df(veri, taban):
                if yakalayan is None:
                    yakalayan, gecikme = dad, adim
    sunum = veri if isinstance(veri, dict) and veri and isinstance(
        list(veri.values())[0], float) else None
    return sunum, iz, yakalayan, gecikme


def taban_kur(kaynak):
    v1, _ = a1_ayikla(kaynak)
    v2, _ = a2_tekille(v1)
    v3, _ = a3_tuketim(v2)
    oz, _ = a4_ozet(v3)
    sun, _ = a5_sun(oz)
    return {"beklenen_satir": len(kaynak), "taban_ozet": oz, "taban_sunum": sun}


kaynak = kaynak_uret()
taban = taban_kur(kaynak)
DUZENEK = [("veri ambari", ["sema", "tip"]),        # kapi yalnizca satira bakar
           ("veri golu", []),                       # hicbir dayatma yok
           ("gol evi", None)]                       # butun denetimler okuma aninda


def yaz_hucre(y, g):
    return f"{y}/{g}" if y else "-"


gecikme_kaydi = {ad: [] for ad, _ in DUZENEK}
print(f"{'sinif':<15}{'veri ambari':>14}{'veri golu':>11}{'gol evi':>16}")
for s in BOZULMA:
    gelen, _ = boz(kaynak, s)
    hucre = []
    for ad, acik in DUZENEK:
        _, _, y, g = denetimli_hat(gelen, taban, acik=acik)
        if y:
            gecikme_kaydi[ad].append(g)
        hucre.append(yaz_hucre(y, g))
    print(f"{s:<15}{hucre[0]:>14}{hucre[1]:>11}{hucre[2]:>16}")
for ad, _ in DUZENEK:
    v = gecikme_kaydi[ad]
    ort = f"{sum(v) / len(v):.2f}" if v else "tanimsiz"
    print(f"{ad:<15}yakalanan {len(v)}/{len(BOZULMA)}  ortalama gecikme {ort}")
```

```
sinif             veri ambari  veri golu         gol evi
gec_gelen                   -          -       dagilim/4
yinelenen                   -          -      tekillik/0
sema_degisti           sema/0          -          sema/0
birim_degisti               -          -       dagilim/4
eksik_bolum                 -          -   bolum_donem/0
kayan_tip               tip/0          -           tip/0
veri ambari    yakalanan 2/6  ortalama gecikme 0.00
veri golu      yakalanan 0/6  ortalama gecikme tanimsiz
gol evi        yakalanan 6/6  ortalama gecikme 1.33
```

Son sütun Veri Mühendisliğine Giriş kursunun ilk yakalayan denetim sütununun **birebir aynısıdır**;
göl evi düzeneği o kursun tam denetimli hattıyla aynı sonucu veriyor, çünkü dayatmanın **nerede**
durduğu değişse de denetim kümesi değişmiyor. Karşılaştırma bu yüzden geçerlidir: üç sütun aynı
cetvelle, aşama birimiyle okunuyor.

Kazanç kapsam tarafındadır. Yazma kapısı **2/6**, hiçbir dayatması olmayan düzenek **0/6**, okuma
anında dayatan düzenek **6/6** yakalıyor. Kapının yakalayamadığı dört sınıf yalnız gözden kaçmıyor;
kapı onları **görebilecek konumda değil**, çünkü ikisi küme, ikisi özet kapsamı gerektiriyor ve bu
kapsamlar yazma anında henüz oluşmamıştır.

Ortalama gecikme satırı dikkatle okunmalıdır. Ambarın **0,00** değeri göl evinin **1,33** değerinden
küçüktür, ama bu ambarın daha hızlı yakaladığı anlamına gelmez. İki ortalama **farklı sayıda sınıf
üzerinden** alınmıştır: ambarınki yalnız yakaladığı iki sınıfın, göl evininki altı sınıfın
ortalamasıdır. Göl evinin yakaladığı iki ortak sınıf, yani `sema_degisti` ile `kayan_tip`, orada da
**0 aşamada** yakalanıyor; dayatmanın okuma anına taşınması bu ikisini **hiç geciktirmiyor**.
Ortalamanın 0,00'dan 1,33'e çıkmasının tek nedeni, ambarda **tanımsız** olan dört değerin sonlu hâle
gelmesidir: 0, 0, 4 ve 4. Bu, Veri Mühendisliğine Giriş kursundaki ayrımın depolama tarafındaki
karşılığıdır: **tanımsız bir gecikme sıfırdan iyi değildir, ölçülmemiş olandır.** Bir düzeneğin
ortalama gecikmesi, kaç sınıfı hiç yakalamadığı yazılmadan okunamaz.

## Ham Katmanın Kurtardığı ve Ödettiği

Gecikme tablosu iki düzeneğin `sema_degisti` karşısında aynı sonucu verdiğini gösteriyor: ikisi de
sıfır aşamada yakalıyor. Ayrıldıkları yer **yakaladıktan sonra ne yaptıklarıdır**. Ambar satırı
reddeder, göl evi ham katmanda tutar ve okuma anında onarır.

```python
SEMA = {"abone": str, "donem": str, "bolge": str, "tip": str, "endeks": int, "birim": str}
ESLEME = {"endeks_degeri": "endeks"}


def uymayan(k):
    return any(a not in k or not isinstance(k[a], t) for a, t in SEMA.items())


def kapida_ele(kayitlar):
    """Ambar: uymayan satir hic yazilmaz."""
    kabul = [k for k in kayitlar if not uymayan(k)]
    return kabul, len(kayitlar) - len(kabul)


def okuma_aninda_onar(kayitlar):
    """Gol evi: ham katman korunur , dayatma okuma aninda onarimla uygulanir."""
    y = []
    for k in kayitlar:
        if uymayan(k):
            k = dict(k)
            for eski, yeni in ESLEME.items():
                if eski in k and yeni not in k:
                    k[yeni] = k.pop(eski)
            if isinstance(k.get("endeks"), str) and k["endeks"].isdigit():
                k["endeks"] = int(k["endeks"])
        y.append(k)
    return y


def hattan(kayitlar):
    v = kayitlar
    for f in (a1_ayikla, a2_tekille, a3_tuketim):
        v, _ = f(v)
    return v


def hucre(kayitlar):
    return sum(len(k) for k in kayitlar)


bozuk, _ = boz(kaynak, "sema_degisti")
kabul, red = kapida_ele(bozuk)
onarilmis = okuma_aninda_onar(bozuk)
print("sema_degisti altinda uc duzenek")
print(f"{'duzenek':<14}{'reddedilen':>11}{'ham katman':>12}{'duzenli satir':>15}"
      f"{'saklanan hucre':>16}")
for ad, ham, duzenli_kaynak in [("veri golu", bozuk, bozuk),
                                ("veri ambari", [], kabul),
                                ("gol evi", bozuk, onarilmis)]:
    d = hattan(duzenli_kaynak)
    h = hucre(ham) + (hucre(d) if ad != "veri golu" else 0)
    print(f"{ad:<14}{red if ad == 'veri ambari' else 0:>11}{len(ham):>12}{len(d):>15}{h:>16}")
temiz = hattan(kaynak)
print("temiz kaynakta saklanan hucre  gol", hucre(kaynak), " ambar", hucre(temiz),
      " gol evi", hucre(kaynak) + hucre(temiz))
```

```
sema_degisti altinda uc duzenek
duzenek        reddedilen  ham katman  duzenli satir  saklanan hucre
veri golu               0        2400           1800           14400
veri ambari           200           0           1800           12600
gol evi                 0        2400           2200           29800
temiz kaynakta saklanan hucre  gol 14400  ambar 15400  gol evi 29800
```

Kazandırdığı üçüncü sütunda: göl evi **2200** düzenli satır üretiyor, öbür iki düzenek **1800**.
Dört yüz satırlık farkın yarısı doğrudan reddedilen kayıtlardır, öteki yarısı ise onların
dolaylı sonucudur; alan adı değişen dönem düştüğünde bir sonraki dönemin tüketim farkı da
hesaplanamaz hâle gelir. Ambarın kaybı bu yüzden reddettiği satır sayısından **büyüktür** ve bu
büyümeyi kapının kendisi bildirmez. Göl evinde ham katman durduğu için eşleme tablosu yazıldığı anda
her iki dönem de geri gelir.

Kaybettirdiği son sütunda: göl evi **29800** hücre saklıyor, ambar **12600**, göl **14400**. Temiz
kaynakta oran daha nettir: 14400, 15400 ve 29800. Göl evi ikisinin toplamını saklar, çünkü aynı
veriyi hem ham hem düzenli biçimde tutar. Sorgu maliyetinde ambarın seviyesindedir, yani 520; ham
katmanı da 14520 ile sorgulanabilir. Yani göl evinin aldığı şey **saklama hücresi karşılığında
alınmış bir seçenektir**: düzenli katman bozulduğunda ya da şema anlayışı değiştiğinde yeniden
üretilebilir.

Kursun ikinci iddiası burada da yazılır: **düzen de bozar.** Göl evinin hiçbir satırı reddetmemesi,
düzenli katmanının temiz olduğu anlamına gelmez. `birim_degisti` satırı bunun kanıtıdır: kapıya
takılmıyor, onarım gerektirmiyor, düzenli katmana **2200 satırın tamamı** yazılıyor ve bozulma
ancak **dördüncü aşamada** görülüyor. O noktaya kadar düzenli katman kusursuz görünen bir şemaya
sahip, tam sayıda satır taşıyan ve iki dönemi bin katına çıkmış bir tablodur. Şemaya uymak doğru
olmakla aynı şey değildir; okuma anına taşınan dayatma bu farkı kapatmaz.

## Özet

- Göl evi ham katmanı korur ve şema dayatmasını yazma anından okuma anına taşıyarak tek bir yerde
  toplar; sonucu şemaya uyumlu bir düzenli katmandır.
- Yakalanan bozulma sınıfı yazma kapısında 2/6, hiçbir dayatması olmayan düzenekte 0/6, okuma anında
  dayatan düzenekte 6/6.
- Ortalama yakalama gecikmesi ambarda 0,00 ve göl evinde 1,33 aşamadır; ortak iki sınıf ikisinde de
  0 aşamada yakalandığına göre ortalamanın yükselmesi kötüleşme değil, tanımsız dört değerin sonlu
  hâle gelmesidir.
- Alan adı değişimi altında göl evi 2200 düzenli satır üretiyor, öbür iki düzenek 1800; kaybın
  yarısı reddedilen satır, yarısı onların düşürdüğü bir sonraki dönemdir.
- Bedel saklanan hücredir: temiz kaynakta göl 14400, ambar 15400, göl evi 29800.
- Okuma anında dayatma bozuk satırın düzenli katmana yazılmasını engellemez; `birim_degisti` hiçbir
  kapıya takılmadan 2200 satır olarak yazılıyor ve dördüncü aşamada görülüyor.

## Sonraki Adım

Üç ders depolamanın **ne sakladığını** birbirinden ayırdı. Ambar şemaya uyumlu satırı, göl gelen
satırın kendisini, göl evi ikisini birden saklıyor ve her seçimin sorguya, yakalamaya ve saklanan
hücreye ödettiği ayrı ayrı yazıldı. Üç derste hiç sorulmayan bir soru var: bu satırlar **kimin
için** saklanıyor. Üç düzeneğin de tek bir tüketiciye hizmet ettiği varsayıldı, oysa aynı ambardan
okuyan taraflar farklı sorular sorar ve farklı sütunlara bakar. Bir bölgeyle ilgilenen taraf bütün
bölgeleri taşıyan bir düzeni her sorguda baştan süzmek zorunda kalır. Sonraki ders bu soruyu
sorar ve alan odaklı alt kümeleri, yani **veri pazarlarını** ölçer; ölçüsü iki sayının yan yana
durmasıdır: alt küme ayrı yazıldığında sorgu maliyeti ne oluyor ve **aynı satır kaç yerde duruyor**.
