İçeriğe geç
academia.sh

Ders 10 / 12

Sütunlu Dosya Biçimleri

Seçici okumanın ve sıkıştırmanın okunan hücre üzerinden sayılması: iki sütun seçildiğinde sütunlu okuma 400 hücre ve 520 maliyet, satırlı okuma 1400 hücre ve 1520 maliyet veriyor; seçilen sütun sayısı arttıkça fark 200'er hücre kapanıyor ve yedinci sütunda tam olarak sıfırlanıyor, yani sütunlu biçimin kazancı sorgunun okumadığı sütun kadar. Sıkıştırma okunan hücre üzerinden modellendiğinde bu kapanma noktası tablodan çıkıyor: yedi sütunun tamamı sütunlu düzende 851, satırlı düzende 1400 hücre. Kazanç ayrık değer sayısının değil koşu sayısının işi; bölge sütunu beş ayrık değer taşırken 158 koşu veriyor. Dosya içi sıralama tek bir sorgu için seçilir: bölge ile tipe göre sıralamak o sorguyu 253 hücreden 15'e indiriyor ama metreküp sütununu 196'dan 200'e, yani sıkıştırmasız değere geri çıkarıyor.

İçindekiler

Önceki üç ders tablonun şeklini tartıştı: olgu ile boyutun ayrılması, normalleştirme derecesinin birleştirmeye ödettiği, tarihçe tutmayan boyutun cevabı sessizce yanlışlaması. Üçünde de tablo mantıksal bir nesne olarak durdu — satırları, sütunları ve bir sonucu olan bir küme. Bir şey hiç sorulmadı: bu tablo diske indiğinde ne yan yana duruyor, satırlar mı sütunlar mı.

Bu dersin ölçtüğü şey o karardır. Ölçü değişmez: dokunulan dosya, okunan hücre ve maliyet. Değişen tek şey, aynı sorgunun aynı dosyadan kaç hücre okumak zorunda kaldığıdır. İki soru sırayla yanıtlanır. Seçici okuma ne kazandırıyor ve bu kazanç nerede biter; sıkıştırma o sınırı nereye taşır.

  • AM41. Kaynak, hattan çıkan tüketim satırları ve dosya düzeni kurgudur ve ders içinde üretilir. Hiçbir ambar, göl, dosya biçimi ya da sorgu motoru çağrılmaz. Tohum 20260218.
  • AM42. Sütunlu dosya biçimi (columnar file format) ve satırlı dosya biçimi (row-oriented file format) birer sınıf adıdır. Ayrım tek bir davranıştadır: sütunlu okuma yalnız seçilen sütunları alır, satırlı okuma kaydın tamamını alır.
  • AM43. Kayıt yedi sütun taşır. Okunan hücre, dokunulan satır ile okunan sütunun çarpımıdır.
  • AM44. Maliyet, dosya sayısı ile dosya sabiti 120’nin çarpımına okunan hücrenin eklenmesidir. Sabit bir seçimdir; bu derste iki düzen de aynı tek dosyaya dokunduğu için sabit farkın dışında kalır.
  • AM45. Sıkıştırma okunan hücre üzerinden modellenir, algoritma yazılmaz. Bir sütunun sıkışmış bedeli o sütundaki koşu (run) sayısıdır: dosya sırasında ardışık duran aynı değerler tek hücreye iner. Sıkıştırma yordamı Linux ve Sistem Yönetimi müfredatındaki Linux’a Giriş kursunda ölçüldü; tekrarlanmaz.
  • AM46. Satırlı düzende koşu birimi kaydın tamamıdır. Abone ile dönem çiftleri tekil olduğu için ardışık iki kayıt hiçbir zaman eşit değildir ve daralma olmaz.
  • AM47. Dosya içi sıralama bir yazma kararıdır ve dosya başına tek olabilir.
  • AM48. Bölüm anahtarı bu derste sabittir ve donem’dir. Anahtarın kendisi sonraki dersin konusudur.

Seçici Okumanın Ödettiği

Sorgu tek bir dönemin bölge bazlı tüketimini istiyor; ihtiyacı olan iki sütun var, bolge ve m3. Aşağıdaki blok hattı, düzeni ve maliyet ölçüsünü kurar, sonra aynı sorguyu seçilen sütun sayısını birden yediye çıkararak süpürür.

# KURGUDUR. Olcum aginin sayac okumalari , tuketim satirlari ve dosya duzeni ders
# icinde uretilir; hicbir ambar , gol , dosya bicimi ya da sorgu motoru cagrilmaz.
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)]
SUTUN = ("abone", "donem", "bolge", "tip", "endeks", "birim", "m3")
DOSYA_SABIT = 120          # bir dosyaya dokunmanin sabit bedeli , hucre cinsinden
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 satirlar():
    """Hattan cikan tuketim satirlari. Saglam kaynakta ayikla ve tekille asamalari
    satir dusurmedigi icin tuketim dogrudan kaynaktan , donem farkiyla hesaplanir."""
    ham = []
    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)
            ham.append({"abone": ab, "donem": d, "bolge": a["bolge"], "tip": a["tip"],
                        "endeks": e, "birim": "m3"})
    tablo, cikti = {(k["abone"], k["donem"]): k for k in ham}, []
    for k in ham:
        i = DONEM.index(k["donem"])
        onceki = tablo.get((k["abone"], DONEM[i - 1])) if i else None
        if onceki is not None:
            cikti.append(dict(k, m3=k["endeks"] - onceki["endeks"]))
    return cikti


def yaz(kayitlar, bolumleme=()):
    """Satirlari bolumleme anahtarina gore dosyalara dagitir."""
    duzen = {}
    for k in kayitlar:
        duzen.setdefault(tuple(k[a] for a in bolumleme), []).append(k)
    return duzen


def sorgu(duzen, bolumleme, secilen, suzgec=None, sutunlu=True):
    """Dokunulan dosya , okunan hucre ve maliyet = dosya x DOSYA_SABIT + hucre.
    Sutunlu okuma yalniz secilen sutunlari , satirli okuma kaydin tamamini alir."""
    suzgec = {} if suzgec is None else suzgec
    budayan = {a: v for a, v in suzgec.items() if a in bolumleme}
    dosya, hucre = 0, 0
    genislik = len(secilen) if sutunlu else len(SUTUN)
    for anahtar, kayit in duzen.items():
        if budayan:
            es = dict(zip(bolumleme, anahtar))
            if any(es[a] != v for a, v in budayan.items()):
                continue
        dosya += 1
        hucre += len(kayit) * genislik
    return {"dosya": dosya, "hucre": hucre, "maliyet": dosya * DOSYA_SABIT + hucre}


SATIR = satirlar()
DUZEN = yaz(SATIR, ("donem",))
EKLEME = ["bolge", "m3", "abone", "tip", "birim", "endeks", "donem"]
print(f"hattan cikan satir {len(SATIR)} , donem duzeninde dosya {len(DUZEN)} ,"
      f" dosya basina satir {len(SATIR) // len(DUZEN)}")
print("\nsecilen sutun   sutunlu hucre  maliyet   satirli hucre  maliyet   fark")
for n in range(1, len(SUTUN) + 1):
    sec = tuple(EKLEME[:n])
    a = sorgu(DUZEN, ("donem",), sec, {"donem": "2026-07"}, True)
    b = sorgu(DUZEN, ("donem",), sec, {"donem": "2026-07"}, False)
    print(f"{n:>13}   {a['hucre']:>13}  {a['maliyet']:>7}   {b['hucre']:>13}"
          f"  {b['maliyet']:>7}   {b['maliyet'] - a['maliyet']:>4}")
hattan cikan satir 2200 , donem duzeninde dosya 11 , dosya basina satir 200

secilen sutun   sutunlu hucre  maliyet   satirli hucre  maliyet   fark
            1             200      320            1400     1520   1200
            2             400      520            1400     1520   1000
            3             600      720            1400     1520    800
            4             800      920            1400     1520    600
            5            1000     1120            1400     1520    400
            6            1200     1320            1400     1520    200
            7            1400     1520            1400     1520      0

İkinci satır dersin başlangıç sayısıdır. Aynı dosyaya, aynı 200 satıra, aynı süzgeçle dokunan iki düzenden biri 400 hücre okuyup 520 ödüyor, öbürü 1400 hücre okuyup 1520 ödüyor. Hiçbiri daha akıllı değildir; biri sorgunun istemediği beş sütunu almak zorundadır, öbürü değildir.

Tablonun asıl bulgusu sağdaki iki sütunun sabitliğidir. Satırlı okuma 1400 hücrede durur ve seçilen sütun sayısına hiç tepki vermez, çünkü kaydın tamamını zaten ilk sorguda almıştır. Sütunlu okuma her eklenen sütunla tam 200 hücre büyür. Fark bu yüzden düzenli iner: 1200, 1000, 800, 600, 400, 200 ve yedinci sütunda 0.

Kapanma noktası bir eşik değil, bir tanımdır. Sütunlu biçimin kazandırdığı şey sorgunun okumadığı sütun sayısıdır, ne eksik ne fazla. Yedinci sütunda kazanç sıfırlanır, çünkü orada sorgu zaten kaydın tamamını istemektedir. Bir düzenin “sütunlu olduğu için hızlı” diye anılması bu tablonun okunmadığı anlamına gelir: iki sütun okuyan sorgu için doğru, yedi sütun okuyan sorgu için yanlıştır.

Dosya sabitinin bu tabloda payı yoktur. İki düzen de tek dosyaya dokunduğu için maliyetin sabit parçası ikisinde de 120’dir ve maliyet farkı hücre farkına birebir eşittir. Sabit 60 ya da 480 olsaydı sağdaki sütun değişmezdi. Bu, sabite duyarsız bir sonuçtur ve sonraki derste tersi görülür.

Sıkıştırma Okunan Hücre Üzerinden Ölçülür

Yukarıdaki model her hücreyi bir birim sayar. Sütunlu düzenin ikinci kazancı buradadır: bir sütunun bütün değerleri bitişik durduğu için ardışık tekrarlar tek hücreye inebilir. Aşağıdaki blok bu daralmayı koşu sayısıyla ölçer ve dosyanın yedi sütununu tek tek sayar.

# Bu blok ilk bloktaki SUTUN , DOSYA_SABIT , satirlar() ve yaz() tanimlarini surdurur.
def kosu(degerler):
    """Ardisik ayni degerlerin olusturdugu blok sayisi."""
    n, onceki = 0, object()
    for d in degerler:
        if d != onceki:
            n += 1
            onceki = d
    return n


def sik_hucre(kayit, secilen, sutunlu=True):
    """Sikismis okuma , hucre cinsinden. Sutunlu duzende her sutun kendi icinde
    bitisiktir ve ardisik ayni deger tek hucreye iner; satirli duzende kayit butun
    olarak durur , iki kaydin anahtari ayni olmadigi icin daralma olmaz."""
    if not sutunlu:
        return len(kayit) * len(SUTUN)
    return sum(kosu([k[s] for k in kayit]) for s in secilen)


DOSYA = yaz(satirlar(), ("donem",))[("2026-07",)]
print(f"tek dosya , donem 2026-07 , satir {len(DOSYA)}")
print("\nsutun     ayrik deger   kosu   sikismamis   sikismis")
for s in SUTUN:
    print(f"{s:<9} {len(set(k[s] for k in DOSYA)):>11}   {kosu([k[s] for k in DOSYA]):>4}"
          f"   {len(DOSYA):>10}   {kosu([k[s] for k in DOSYA]):>8}")
ham, sik = len(DOSYA) * len(SUTUN), sik_hucre(DOSYA, SUTUN)
sat = sik_hucre(DOSYA, SUTUN, False)
print(f"\nyedi sutun , sutunlu sikismamis: hucre {ham} , maliyet {ham + DOSYA_SABIT}")
print(f"yedi sutun , sutunlu sikismis  : hucre {sik} , maliyet {sik + DOSYA_SABIT}")
print(f"yedi sutun , satirli           : hucre {sat} , maliyet {sat + DOSYA_SABIT}")
tek dosya , donem 2026-07 , satir 200

sutun     ayrik deger   kosu   sikismamis   sikismis
abone             200    200          200        200
donem               1      1          200          1
bolge               5    158          200        158
tip                 2     95          200         95
endeks            200    200          200        200
birim               1      1          200          1
m3                 46    196          200        196

yedi sutun , sutunlu sikismamis: hucre 1400 , maliyet 1520
yedi sutun , sutunlu sikismis  : hucre 851 , maliyet 971
yedi sutun , satirli           : hucre 1400 , maliyet 1520

Önceki bölümün kapanma noktası bu blokla tablodan çıkar. Yedi sütunun tamamını okuyan sorgu sütunlu düzende 851 hücre, satırlı düzende 1400 hücre okur; maliyet 971’e karşı 1520’dir. Seçici okumanın kazancı bittiği yerde sıkıştırmanın kazancı sürer ve fark 549 hücrede durur.

Koşu sütunu ile ayrık değer sütununun ayrışması dersin en yanıltıcı yeridir. bolge beş ayrık değer taşır, buna karşın 158 koşu verir: dosya abone sırasında yazıldığı için beş değer iki yüz satıra serpilmiştir ve neredeyse hiç ardışık tekrar yoktur. donem ile birim tek değer taşır ve 1 hücreye iner; ikisi de dosya boyunca değişmez. Sıkışan şey az sayıda farklı değer değil, yan yana duran aynı değerdir.

abone ile endeks sütunları bunun karşı ucudur. İkisi de satır başına tekil olduğu için 200 koşu verir ve sıkışmamış değerle birebir aynı kalır. Bu iki sütunu okuyan bir sorgu sütunlu düzende hiçbir sıkıştırma kazancı görmez.

Sıralama Tek Bir Sorgu İçin Seçilir

Koşu sayısı dosyanın yazılış sırasına bağlıdır, dolayısıyla bir yazma kararıyla değiştirilebilir. Aşağıdaki blok aynı dosyayı üç ayrı sırayla yazıp üç sorgunun okuduğu hücreyi karşılaştırır.

# Bu blok onceki iki bloktaki tanimlari surdurur.
SIRALAMA = {"abone (dogal)": lambda k: (k["abone"],),
            "bolge , tip": lambda k: (k["bolge"], k["tip"]),
            "m3": lambda k: (k["m3"],)}
SORGU = {"bolge+tip": ("bolge", "tip"), "m3": ("m3",), "abone+endeks": ("abone", "endeks")}
DOSYA = yaz(satirlar(), ("donem",))[("2026-07",)]
print("tek dosya , okunan hucre ; parantez icinde maliyet = 1 x 120 + hucre")
print("\nsiralama         " + "".join(f"{a:>16}" for a in SORGU) + "      yedi sutun")
for ad, anahtar in SIRALAMA.items():
    s = sorted(DOSYA, key=anahtar)
    h = [sik_hucre(s, sec) for sec in SORGU.values()] + [sik_hucre(s, SUTUN)]
    print(f"{ad:<15} " + "".join(f"{f'{x} ({x + DOSYA_SABIT})':>16}" for x in h))
h = [len(DOSYA) * len(sec) for sec in SORGU.values()] + [len(DOSYA) * len(SUTUN)]
print(f"{'sikistirmasiz':<15} " + "".join(f"{f'{x} ({x + DOSYA_SABIT})':>16}" for x in h))
tek dosya , okunan hucre ; parantez icinde maliyet = 1 x 120 + hucre

siralama                bolge+tip              m3    abone+endeks      yedi sutun
abone (dogal)          253 (373)       196 (316)       400 (520)       851 (971)
bolge , tip             15 (135)       200 (320)       400 (520)       617 (737)
m3                     252 (372)        46 (166)       400 (520)       700 (820)
sikistirmasiz          400 (520)       200 (320)       400 (520)     1400 (1520)

İkinci satır kazancın en büyüğüdür. Dosya bölgeye ve tipe göre sıralandığında bu iki sütunu okuyan sorgu 253 hücreden 15 hücreye iner, maliyet 373’ten 135’e düşer. Beş bölge ile iki tip artık bitişik bloklar hâlinde durmaktadır ve on beş koşu bütün dosyayı anlatmaya yetmektedir.

Aynı satırın ikinci sütunu bu kursun ikinci iddiasını taşır: düzen de bozar. Bölgeye göre sıralamak m3 sütununu 196 koşudan 200 koşuya çıkarır. Sayı küçüktür ama yönü nettir — o sütun için sıralama yalnızca yararsız değil, doğal sıradan kötüdür ve sıkıştırmasız değerle (200) birebir aynı yere oturur. Metreküp sütununu okuyan sorgu, bölge sorgusu için alınmış bir karar yüzünden sıkıştırmanın tamamını kaybeder.

Üçüncü satır aynı takası ters yönden gösterir. Dosya metreküpe göre sıralandığında o sütun 46 hücreye iner, buna karşılık bölge ile tip 252‘de kalır, yani doğal sıradaki 253’ten ayırt edilemez. Bir dosyanın tek bir sıralaması olabilir; ikisi aynı anda seçilemez.

Son sütun kararın toplam bedelini verir: yedi sütunun tamamı doğal sırada 851, bölge sırasında 617, metreküp sırasında 700 hücre. Üç sayı da satırlı düzenin 1400’ünün altındadır, ama hangisinin seçileceği yalnızca hangi sorgunun adının yazıldığına bağlıdır. Sıralaması bir sorgu adı olmadan seçilmiş bir dosya, kursun kuralı gereği ölçülmemiştir.

Özet

  • Sütunlu ve satırlı biçim arasındaki fark tek bir davranıştır: sütunlu okuma seçilen sütunları, satırlı okuma kaydın tamamını alır. İki sütunluk sorguda sütunlu düzen 400 hücre / 520 maliyet, satırlı düzen 1400 hücre / 1520 maliyet öder.
  • Seçici okumanın kazancı sorgunun okumadığı sütun kadardır ve her eklenen sütunla 200 hücre erir; yedinci sütunda tam olarak sıfırlanır. İki düzen de tek dosyaya dokunduğu için dosya sabiti 120 bu farkın dışında kalır.
  • Sıkıştırma okunan hücre üzerinden modellendiğinde kapanma noktası tablodan çıkar: yedi sütunun tamamı sütunlu düzende 851, satırlı düzende 1400 hücredir.
  • Sıkışan şey az sayıda ayrık değer değil, yan yana duran aynı değerdir: bolge beş ayrık değerle 158 koşu verirken donem tek değerle 1 koşuya iner; satır başına tekil olan abone ve endeks hiç sıkışmaz.
  • Dosya içi sıralama bir sorgu için seçilir ve başka bir sorgunun kazancını götürür: bölge ile tipe göre sıralamak o sorguyu 253’ten 15 hücreye indirirken m3 sütununu 196’dan 200’e, yani sıkıştırmasız değerine geri çıkarır.

Sonraki Adım

Bu dersin bütün sayıları tek bir dosyanın içinde ölçüldü. Bölüm anahtarı donem olarak sabit tutuldu, süzgeç hep o anahtarın üstüne düştü ve her sorgu tek dosyaya dokundu; dosya sabiti bu yüzden hiçbir farkı değiştirmedi. Anahtarın kendisi hiç sorgulanmadı. Sonraki ders bu sabiti kaldırır ve iki soruyu sorar: süzgeç bölüm anahtarının dışında bir alana düştüğünde ne oluyor, ve aynı veriyi daha çok dosyaya bölmek — okunan hücre hiç artmasa bile — maliyeti nereye taşıyor.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat