B-Tree ve B+ Tree nedir? Ekleme, bölme (split), silme, birleştirme (merge) işlemleri, B+ Tree farkları ve veritabanı indeksleme mantığı — görsellerle anlatım.

B-Tree ve B+ Tree nedir? Ekleme, bölme (split), silme, birleştirme (merge) işlemleri, B+ Tree farkları ve veritabanı indeksleme mantığı — görsellerle anlatım.

🗂️ Veri Yapıları 📅 21 February 2026 👁️ 6 görüntülenme

Neden B-Tree? — Disk Erişim Problemi

Şimdiye kadar öğrendiğimiz ağaçlar (BST, AVL, RB) RAM'de çalışmak üzere tasarlanmıştır. Bir düğüme erişmek nanosaniyeler sürer. Ancak veritabanları ve dosya sistemleri verilerini diskte saklar — ve disk erişimi dramatik şekilde yavaştır.

RAM vs Disk — Erişim Hızı Karşılaştırması
DepolamaErişim SüresiHız Farkı
L1 Cache~1 ns
RAM~100 ns100×
SSD~100 μs100.000×
HDD~10 ms10.000.000×
Disk, RAM'den 100.000 – 10.000.000 kat yavaştır. Her disk okuması pahalıdır!

Bir AVL ağacında 1 milyon anahtar varsa yükseklik ~20'dir. Her arama 20 düğüm erişimi gerektirir — RAM'de sorun olmaz ama diskte 20 ayrı disk okuması demektir. Çözüm: her düğüme çok sayıda anahtar koyarak ağacın yüksekliğini düşürmek. İşte B-Tree'nin temel fikri budur.

B-Tree temel fikri: Her düğüm bir disk sayfası (4 KB – 16 KB) kadar veri tutar. Bir düğümde yüzlerce anahtar olabilir → ağaç yüksekliği çok düşer. 1 milyon anahtar, t=500 olan B-Tree'de sadece 2-3 seviye → 2-3 disk okuması yeterli!

AVL ile 1.000.000 anahtar

Yükseklik ≈ 20
Arama = 20 disk I/O
20 × 10ms = 200ms

B-Tree (t=500) ile 1.000.000 anahtar

Yükseklik ≈ 2-3
Arama = 3 disk I/O
3 × 10ms = 30ms

B-Tree Kuralları

B-Tree, minimum derece t (t ≥ 2) parametresiyle tanımlanan, kendiliğinden dengeli çok yollu arama ağacıdır. 1970'te Rudolf Bayer ve Edward McCreight tarafından geliştirilmiştir.

Kural 1 — Anahtar Sınırları: Her düğüm en fazla 2t - 1, en az t - 1 anahtar tutar (kök hariç). Anahtarlar düğüm içinde sıralıdır.
Kural 2 — Çocuk Sınırları: İç düğümler en fazla 2t, en az t çocuk tutar (kök hariç). Çocuk sayısı = anahtar sayısı + 1.
Kural 3 — Kök İstisnası: Kök düğümde minimum anahtar sayısı 1'dir (boş ağaç hariç). Kök yaprak da olabilir.
Kural 4 — Yaprak Dengesi: Tüm yaprak düğümler aynı derinliktedir. Ağaç aşağıdan değil, yukarıdan büyür (bölme köke propagate eder).
Kural 5 — Arama Kuralı: ki anahtarının solundaki alt ağaçtaki tüm değerler < ki, sağındakiler > ki. (BST'nin çok yollu genellemesi.)

Sayısal Örnekler

ParametreFormült=2t=3t=500
Min anahtart - 112499
Max anahtar2t - 135999
Min çocukt23500
Max çocuk2t461000
Yükseklik (1M kayıt)logt(n)~20~12~2

Referans B-Tree (t = 3)

B-Tree (t=3) — Her düğüm 2–5 anahtar tutar
2040<2020–40>40510152530354550Tüm yapraklar aynı derinlikte (seviye 1) ✓

Düğüm Yapısı ve Arama

btree.c — yapı + arama
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define T  3   // minimum derece

typedef struct BTreeNode {
    int    keys[2*T - 1];       // anahtarlar (sıralı)
    struct BTreeNode* children[2*T]; // çocuk pointer'ları
    int    n;                    // mevcut anahtar sayısı
    bool   leaf;                 // yaprak mı?
} BTreeNode;

BTreeNode* yeniDugum(bool leaf) {
    BTreeNode* node = (BTreeNode*)calloc(1, sizeof(BTreeNode));
    node->leaf = leaf;
    return node;
}

BTreeNode* btreeAra(BTreeNode* node, int key) {
    if (!node) return NULL;
    int i = 0;
    while (i < node->n && key > node->keys[i]) i++;
    if (i < node->n && key == node->keys[i]) return node;
    if (node->leaf) return NULL;
    return btreeAra(node->children[i], key);
}
Gerçek veritabanlarında: children[] pointer yerine disk sayfa numarası tutulur. read_page(page_no) ile diskten okunur. Bu yazıda kavramsal basitlik için RAM pointer kullanıyoruz — ama her pointer erişimini bir disk I/O olarak düşünün.

Ekleme ve Bölme (Insert & Split)

B-Tree'ye ekleme daima bir yaprak düğüme yapılır. Ekleme yapılacak yaprak doluysa (2t-1 anahtar), düğüm ekleme öncesinde bölünür (split). Bölme yukarıya propagate ederek köke kadar çıkabilir — kök bölünürse ağaç yukarıdan büyür.

Proaktif bölme (preemptive split): Kökten yaprağa inerken karşılaşılan her dolu düğüm önceden bölünür. Böylece yaprağa ulaştığında ekleme her zaman yer bulur. Bu tek-geçişli (single-pass) yaklaşım geriye dönüş gerektirmez.

Bölme (Split) İşlemi — Detay

t=3 olan bir düğümde max 5 anahtar vardır. Düğüm doluysa:

Dolu Düğüm Bölme (t=3): 5 anahtar → 2 + 1 (yukarı) + 2
Dolu düğüm (5 anahtar)
10
20
30
40
50
↑ medyan (ortanca)
Bölme sonrası
30
 ↑ ebeveyne çıkar
10
20
40
50
sol çocuk       sağ çocuk
splitChild() — çocuk düğümü böl
void splitChild(BTreeNode* parent, int i) {
    BTreeNode* y = parent->children[i]; // dolu çocuk
    BTreeNode* z = yeniDugum(y->leaf);  // yeni sağ yarı
    z->n = T - 1;

    // Sağ yarının anahtarlarını kopyala
    for (int j = 0; j < T - 1; j++)
        z->keys[j] = y->keys[j + T];
    // Çocukları da kopyala (iç düğümse)
    if (!y->leaf)
        for (int j = 0; j < T; j++)
            z->children[j] = y->children[j + T];
    y->n = T - 1;

    // Ebeveynde yer aç
    for (int j = parent->n; j > i; j--) {
        parent->children[j + 1] = parent->children[j];
        parent->keys[j] = parent->keys[j - 1];
    }
    parent->children[i + 1] = z;
    parent->keys[i] = y->keys[T - 1]; // medyan yukarı
    parent->n++;
}

Adım Adım — B-Tree Ekleme (t=3)

Ekleme sırası: 10, 20, 30, 40, 50, 25, 35, 5

8 Ekleme — Bölme Operasyonları
① +10, +20, +30, +40, +50 → kök doluyor
+10: 
10
  → +50: 
10
20
30
40
50
  DOLU!
② +25 eklenmeden önce kök bölünür → ağaç yukarı büyür
3010204050
30 medyan olarak yeni köke çıktı. Sonra 25 sol çocuğa eklenir →
③ +25 eklendi (sol çocuğa)
301020254050
④ +35 ve +5 eklendi (yer var, bölme gerekmedi)
305102025354050
btreeEkle() — proaktif bölmeli tek geçiş
void insertNonFull(BTreeNode* node, int key) {
    int i = node->n - 1;

    if (node->leaf) {
        // Yaprakta sıralı pozisyona ekle
        while (i >= 0 && key < node->keys[i]) {
            node->keys[i + 1] = node->keys[i];
            i--;
        }
        node->keys[i + 1] = key;
        node->n++;
    } else {
        // Doğru çocuğu bul
        while (i >= 0 && key < node->keys[i]) i--;
        i++;
        // Çocuk doluysa önceden böl
        if (node->children[i]->n == 2*T - 1) {
            splitChild(node, i);
            if (key > node->keys[i]) i++;
        }
        insertNonFull(node->children[i], key);
    }
}

void btreeEkle(BTreeNode** root, int key) {
    BTreeNode* r = *root;
    if (r->n == 2*T - 1) {
        // Kök doluysa yeni kök oluştur ve böl
        BTreeNode* s = yeniDugum(false);
        s->children[0] = r;
        splitChild(s, 0);
        insertNonFull(s, key);
        *root = s;
    } else {
        insertNonFull(r, key);
    }
}
Ekleme garantisi: Her ekleme O(t × logt n) zamanda tamamlanır. Bölme işlemi en fazla yükseklik kadar tekrarlanır. Disk I/O: O(logt n) okuma + O(logt n) yazma.

Silme ve Birleştirme (Delete & Merge)

B-Tree'den silme, eklemeden çok daha karmaşık bir operasyondur. Temel kısıt: silme sonrası hiçbir düğüm t-1'den az anahtar tutmamalıdır (kök hariç). Bu kısıtı korumak için ödünç alma (redistribution) ve birleştirme (merge) mekanizmaları devreye girer.

Eklemedeki proaktif bölme mantığına benzer şekilde, silmede de proaktif takviye (preemptive fix-up) uygulanır: kökten yaprağa inerken yolumuzun üzerindeki her düğümün en az t anahtarı olduğundan emin oluruz. Böylece yaprağa ulaştığında güvenle silebiliriz.

3 Temel Silme Durumu

Durum 1: Yapraktan Doğrudan Silme

Anahtar yaprak düğümde ve düğümde > t-1 anahtar var → anahtarı çıkar, diğerlerini kaydır. En basit durum.

Durum 2: İç Düğümden Silme

Anahtar iç düğümde → doğrudan silinemez (çocuk pointer'ları bozulur). Anahtar öncül (predecessor) veya ardıl (successor) ile yer değiştirir. Sorun yaprağa taşınmış olur → Durum 1'e dönüşür.

Durum 3: Yetersiz Düğüm (Underflow)

Silinecek anahtar aşağıdaki çocuktaysa ve çocukta tam t-1 anahtar varsa → silme yapılırsa kural ihlal edilir. Önce çocuk takviye edilir: komşudan ödünç al veya birleştir (merge).

Durum 2 Detay — Öncül ve Ardıl

İç düğümden silinen anahtar ki için iki seçenek vardır:

İç Düğümden Silme — Öncül (Predecessor) Stratejisi
① Öncül (in-order predecessor): ki'nin sol alt ağacındaki en büyük anahtar (en sağdaki yaprakta en sağdaki anahtar). Sol çocuğun ≥ t anahtarı varsa bu strateji kullanılır.
② Ardıl (in-order successor): ki'nin sağ alt ağacındaki en küçük anahtar (en soldaki yaprakta en soldaki anahtar). Sağ çocuğun ≥ t anahtarı varsa bu strateji kullanılır.
③ Her ikisi de minimum ise: Sol ve sağ çocuk birleştirilir (merge), sonra birleştirilmiş düğümde rekürsif olarak silinir.
2030222528↑ öncül3235↑ ardıl
30'u silmek için: öncül 28 ile değiştir VEYA ardıl 32 ile değiştir → sorun yaprağa taşınır.

Durum 3 Detay — Underflow Düzeltme Stratejileri

Silme yolundaki bir çocuk düğümde tam t-1 anahtar varsa, silme yapılırsa kural bozulur. İki düzeltme mekanizması vardır:

Strateji A: Komşudan Ödünç Alma (Redistribution / Rotation)
Önce3520t-1=2 anahtar (min!)405060Sonra4020355060
Sağ komşunun fazla anahtarı var (≥t). Ebeveynden 35 sol çocuğa iner, sağ komşunun ilk anahtarı (40) ebeveyne çıkar. AVL rotasyonuna benzer mantık.
Strateji B: Birleştirme (Merge)
Önce3510204050Her iki çocuk da minimum (t-1=2)Sonra (birleşik)102035405035 ebeveynden aşağı indi
Her iki komşu da minimum (t-1) → ebeveynden bir anahtar (35) aşağı iner, iki çocuk ve bu anahtar tek düğümde birleşir. Ebeveyn bir anahtar kaybeder — ebeveyn de minimum ise merge yukarı propagate eder. Kök boşalırsa kaldırılır → ağaç yüksekliği 1 azalır.

Adım Adım — Kapsamlı Silme Örneği

Başlangıç ağacı (t=3):

Başlangıç Durumu — 8 Anahtar
305102025354050
① delete(25) → Durum 1: Yapraktan doğrudan silme
Sol yaprak: 4 anahtar (>t-1=2 ✓)
5
10
20
25
Sonuç: 3 anahtar (≥t-1=2 ✓)
5
10
20
En basit durum — düğümde fazla anahtar var, doğrudan çıkar.
② delete(30) → Durum 2: İç düğümden silme (öncül ile değiştir)
1. 30 kök düğümde (iç düğüm) → doğrudan silinemez.
2. Sol çocuk ≥ t (3 anahtar) → öncül stratejisi kullan.
3. Sol alt ağacın en büyüğü = 20 (öncül).
4. 30 ↔ 20 yer değiştirir → 30 artık yaprakta → Durum 1 olarak silinir.
20510354050
30 → 20 ile değişti, 30 yapraktan silindi.
③ delete(5) → Durum 3: Yaprak minimum → merge gerekli
1. Sol yaprak [5, 10] → tam t-1=2 anahtar (minimum!).
2. Sağ komşu [35, 40, 50] → ≥ t=3 → redistribution (ödünç alma) uygulanabilir.
3. Ebeveynden 20 sol çocuğa iner, sağ komşunun ilk anahtarı (35) ebeveyne çıkar.
4. Sol yaprak artık [5, 10, 20] → 5'i güvenle silebiliriz.
3510204050
5 silindi, rotasyon ile düğümler yeniden dengelendi.
Silme karmaşıklığı — O(t × logt n): Her seviyede en fazla bir merge veya redistribution. Merge köke kadar propagate ederse yükseklik 1 azalır — B-Tree böylece aşağıdan küçülür (ekleme yukarıdan büyütür). Pratikte çoğu silme basit Durum 1'dir.

Ekleme ve Silme Kuralları — Özet Tablosu

DurumKoşulEylem
Ekleme — yer varYaprakta < 2t-1 anahtarSıralı pozisyona ekle
Ekleme — doluYaprakta 2t-1 anahtarSplit → medyan yukarı, iki yarım düğüm
Kök bölmeKök doluysaYeni kök oluştur → yükseklik +1
Silme — Durum 1Yaprakta > t-1 anahtarDoğrudan çıkar
Silme — Durum 2Anahtar iç düğümdeÖncül/ardıl ile değiştir → yaprağa taşı
Silme — Durum 3aÇocuk minimum, komşu > minRedistribution (ödünç al)
Silme — Durum 3bÇocuk minimum, komşu da minimumMerge → ebeveynden anahtar al
Kök mergeKök boşalırsaKökü kaldır → yükseklik -1

B+ Tree — Veritabanlarının Gerçek Tercihi

B-Tree kavramsal olarak mükemmeldir, ancak gerçek dünya veritabanlarının büyük çoğunluğu (MySQL/InnoDB, PostgreSQL, SQLite, Oracle, SQL Server) B-Tree'nin bir varyantı olan B+ Tree kullanır. B+ Tree, B-Tree'nin disk I/O ve aralık sorgusu zayıflıklarını çözer.

B-Tree vs B+ Tree — 3 Kritik Fark

Fark 1: Veri Nerede?

B-Tree: Veri (value/pointer) her düğümde — hem iç hem yaprakta.
B+ Tree: Veri sadece yapraklarda. İç düğümler sadece yol gösterici anahtar (index key) tutar.

Fark 2: Yaprak Bağlantısı

B-Tree: Yapraklar arasında bağlantı yok.
B+ Tree: Yapraklar bağlı liste (linked list) ile birbirine bağlı → sıralı tarama (range scan) çok hızlı.

Fark 3: Anahtar Tekrarı

B-Tree: Her anahtar ağaçta bir kez geçer.
B+ Tree: İç düğümlerdeki anahtarlar yapraklarda tekrar eder. İç düğümler "kopyalar" — asıl veri yaprakta.

B+ Tree Yapısı — Görsel

B+ Tree (t=3) — Yapraklar bağlı liste ile birbirine bağlı
2040sadece index<2020–40≥4051015veriveriveri20253035her anahtarın verisi burada404550veri← → yapraklar arası bağlı liste (sıralı tarama için)20 ve 40 yapraklarda tekrar ediyor (iç düğüm kopyası)

B+ Tree'nin Avantajları — Neden Veritabanları Tercih Eder?

1. Daha fazla anahtar, daha düşük ağaç: İç düğümler veri tutmadığı için aynı disk sayfasına çok daha fazla anahtar sığar. t değeri artar → ağaç daha alçak → daha az disk I/O. Bir 8 KB sayfaya B-Tree'de 50 key+value sığıyorsa, B+ Tree'de 500 key sığabilir.
2. Aralık sorguları (range query) çok hızlı: WHERE age BETWEEN 20 AND 30 → 20'yi bulunca yaprak bağlı listesinde 30'a kadar sıralı ilerle. B-Tree'de ise inorder traversal gerekir (ebeveyne çık-çocuğa in, çok fazla disk I/O).
3. Sıralı tarama (full scan) optimize: Tüm veriyi sıralı okumak gerekirse yapraklardan bağlı liste ile geçmek yeterli → diskten sıralı okuma (sequential I/O) → çok hızlı. B-Tree'de tüm ağacı inorder traverse etmek gerekir → rastgele disk I/O.
4. Tutarlı erişim süresi: B+ Tree'de her arama yaprağa kadar iner → arama derinliği daima aynı. B-Tree'de anahtar herhangi bir seviyede bulunabilir → değişken derinlik. Bu tutarlılık veritabanı optimizasyonu (query planner) için kritiktir.

B-Tree vs B+ Tree — Detaylı Karşılaştırma

ÖzellikB-TreeB+ Tree
Veri konumuHer düğümdeSadece yapraklarda
İç düğümlerAnahtar + veriSadece anahtar (index)
Yaprak bağlantısıYok ✗Bağlı liste ✓
Anahtar tekrarıYok (benzersiz)İç düğümler yaprakta tekrar
Fan-out (dallanma)OrtaÇok yüksek ✓
Ağaç yüksekliğiOrtaDaha düşük ✓
Arama derinliğiDeğişken (1..h)Sabit (h) ✓
Nokta sorgusuHızlı ✓ (erken durabilir)Hızlı ✓ (yaprak)
Aralık sorgusuYavaş (inorder) ✗Çok hızlı (bağlı liste) ✓
Sıralı taramaRastgele I/O ✗Sıralı I/O ✓
Bellek kullanımıDaha az düğümYaprak tekrarı (biraz fazla)
Kullanım alanıDosya sistemleri, genel amaçlıVeritabanları, index ✓

Aralık Sorgusu — B+ Tree vs B-Tree

SELECT * FROM users WHERE age BETWEEN 20 AND 35
B-Tree: Inorder Traversal 😰
1. Ağaçtan 20'yi bul
2. Inorder: ebeveyne çık → sağ çocuğa in
3. Her adımda farklı disk sayfası
4. Rastgele disk I/O — yavaş!
B+ Tree: Yaprak Tarama 🚀
1. Ağaçtan 20'yi bul (yaprak)
2. Bağlı listede → yürü:
20 → 25 → 30 → 35 → dur
3. Sıralı disk I/O — çok hızlı!

B+ Tree Düğüm Yapısı

bplus_tree.c — yapı farkları
typedef struct BPlusNode {
    int    keys[2*T - 1];
    int    n;
    bool   leaf;

    union {
        struct BPlusNode* children[2*T]; // iç düğüm
        struct {
            void* values[2*T - 1];       // yaprak: veri pointer'ları
            struct BPlusNode* next;         // ★ sonraki yaprak
        };
    };
} BPlusNode;

/* B+ Tree aralık sorgusu (range scan) */
void rangeQuery(BPlusNode* root, int lo, int hi) {
    // 1) lo anahtarını içeren yaprağı bul
    BPlusNode* leaf = findLeaf(root, lo);

    // 2) Yapraklardan bağlı liste ile tara
    while (leaf) {
        for (int i = 0; i < leaf->n; i++) {
            if (leaf->keys[i] >= lo && leaf->keys[i] <= hi)
                printf("%d ", leaf->keys[i]);
            if (leaf->keys[i] > hi) return;
        }
        leaf = leaf->next;  // ★ sonraki yaprağa geç
    }
}

Veritabanı İndeksleme Mantığı

Bir veritabanı tablosunda milyonlarca satır olduğunda, SELECT * FROM users WHERE id = 42 sorgusu index olmadan tüm tabloyu taramak zorundadır (full table scan — O(n)). İndeks, arama süresini O(n) → O(log n) düşüren bir veri yapısıdır. Ve bu indeksin arkasında B+ Tree vardır.

İndeks Olmadan vs İndeks İle

Full Table Scan (İndeks Yok)

10 milyon satırlık tabloda id=42'yi bul
→ 10.000.000 satır oku
Disk sayfası ~100 satır → 100.000 disk I/O
~1000 saniye (HDD)

B+ Tree İndeks İle

B+ Tree yüksekliği ~3 (t≈500)
→ 3-4 disk sayfası oku
+ 1 veri sayfası okuma
~40ms (HDD) / ~0.4ms (SSD)

Clustered vs Non-Clustered (Secondary) İndeks

İki Tür İndeks Yapısı
Clustered Index (Birincil)
• Tablo verisi yapraklarda fiziksel olarak sıralı saklanır
• Tablo başına sadece 1 adet (çünkü veri tek sırada olabilir)
• Genellikle PRIMARY KEY üzerinde otomatik oluşur
• Yaprak = asıl tablo satırı
• MySQL/InnoDB: her tablo bir clustered index'tir
Non-Clustered (Secondary) Index
• Ayrı bir B+ Tree yapısı
• Yapraklar satır yerine satır adresini (pointer) tutar
• Tablo başına birden fazla olabilir
• Arama: index → pointer → asıl satır (ekstra I/O)
• CREATE INDEX ile oluşturulur
Clustered vs Secondary İndeks — Yaprak Farkı
Clustered Indexid=1id=2id=3Ali, 25, İstAyşe, 30, AnkCan, 22, İzm↑ Yaprak = Satır verisi (tablo kendisi)Secondary Index (age)age=22age=25age=30→ id=3→ id=1→ id=2↑ Yaprak = Satır adresi (pointer / PK)Secondary → Clustered (ekstra lookup)

SQL İndeks Oluşturma Örnekleri

SQL — indeks oluşturma
-- Clustered index (PRIMARY KEY ile otomatik)
CREATE TABLE users (
    id    INT PRIMARY KEY,   -- ← otomatik clustered B+ Tree
    name  VARCHAR(100),
    age   INT,
    email VARCHAR(255)
);

-- Secondary index (non-clustered)
CREATE INDEX idx_age ON users(age);

-- Composite (bileşik) index — çok sütunlu B+ Tree
CREATE INDEX idx_age_name ON users(age, name);
-- ↑ (age, name) sırasına göre B+ Tree oluşturur
-- WHERE age=25 → kullanır ✓
-- WHERE age=25 AND name='Ali' → kullanır ✓
-- WHERE name='Ali' → kullanMAZ ✗ (leftmost prefix kuralı)

-- EXPLAIN ile indeks kullanımını kontrol et
EXPLAIN SELECT * FROM users WHERE age BETWEEN 20 AND 30;
-- type: range, key: idx_age → B+ Tree range scan ✓
İndeks ne zaman KULLANILMAZ?
• Tablonun küçük kısmı değil, çoğu okunuyorsa (full scan daha hızlı)
• Sütun üzerinde fonksiyon uygulanırsa: WHERE YEAR(date) = 2024 → index atlanır
• Düşük seçicilik (selectivity): cinsiyet gibi sadece 2 değer → B+ Tree verimsiz
• LIKE '%abc' → önek olmadan (wildcard başta) index kullanamaz

Veritabanlarında B+ Tree Kullanımı

Veritabanıİndeks YapısıSayfa BoyutuNotlar
MySQL / InnoDBB+ Tree (clustered)16 KBTablo = clustered index. PK yoksa gizli row ID üzerinde B+ Tree.
PostgreSQLB+ Tree (varsayılan)8 KBHeap table + ayrı B+ Tree index'ler. GiST, GIN, BRIN alternatifleri.
SQLiteB+ Tree4 KBTek dosyalı DB. rowid üzerinde B+ Tree.
OracleB+ Tree (varsayılan)8 KBIOT (Index-Organized Table) = clustered B+ Tree.
SQL ServerB+ Tree8 KBClustered + non-clustered index'ler.
MongoDBB+ Tree (WiredTiger)~4 KBDoküman ID üzerinde varsayılan B+ Tree index.

Gerçek Dünya Disk Sayfası Hesabı

MySQL/InnoDB — 16 KB Sayfa ile Kapasite
Varsayım: Anahtar = 8 byte (BIGINT), pointer = 6 byte → kayıt = 14 byte
Bir sayfaya sığan anahtar: 16384 / 14 ≈ 1170 anahtar (fan-out)
Seviye 1 (kök): 1 sayfa → 1170 anahtar, 1171 çocuk
Seviye 2: 1171 sayfa → 1170 × 1171 ≈ 1.370.000 anahtar
Seviye 3: 1171² sayfa → 1170 × 1171² ≈ 1.6 milyar anahtar

→ 1.6 milyar kayıt, sadece 3 disk I/O ile erişilebilir!

Karmaşıklık Analizi

OperasyonB-TreeB+ TreeDisk I/O
Arama (nokta)O(logt n)O(logt n)O(logt n)
EklemeO(t × logt n)O(t × logt n)O(logt n)
SilmeO(t × logt n)O(t × logt n)O(logt n)
Aralık sorgusu (k sonuç)O(k × logt n)O(logt n + k)O(logt n + k/B)
Sıralı tarama (tümü)O(n)O(n) — sıralı I/O ✓O(n/B)
Min / MaxO(logt n)O(logt n)O(logt n)
B = bir disk sayfasına sığan kayıt sayısı. t büyüdükçe logt n çok küçülür: log500(109) ≈ 3.3

B+ Tree vs Diğer Yapılar — Genel Karşılaştırma

YapıAramaAralıkEklemeDisk I/OKullanım
Hash IndexO(1)Yapamaz ✗O(1)1 I/O= eşitlik sorgusu
AVL / RBTreeO(log n)O(log n + k)O(log n)O(log n) ✗RAM içi
B-TreeO(logt n)O(k logt n)O(logt n)O(logt n)Dosya sistemi
B+ TreeO(logt n)O(logt n+k) ✓O(logt n)O(logt n) ✓Veritabanı ✓
LSM-TreeO(log n)O(log n + k)O(1) ort.Yazma optimizeNoSQL (Cassandra)

Gerçek Dünya Kullanımları

AlanB-Tree / B+ Tree Kullanımı
İlişkisel VeritabanlarıMySQL, PostgreSQL, Oracle, SQL Server — tüm index'ler B+ Tree
NoSQL VeritabanlarıMongoDB (WiredTiger), CouchDB — doküman index'leme
Dosya SistemleriNTFS, HFS+, ext4 (htree), Btrfs (adında B-Tree var!) — dosya/dizin araması
Key-Value DepolarıBoltDB, LMDB, LevelDB — B+ Tree veya LSM-Tree
Arama MotorlarıInverted index (ters çevrilmiş indeks) altında B+ Tree
GIS / Coğrafi SorgularR-Tree (B-Tree'nin çok boyutlu genellemesi)

Sonuç

B-Tree ve B+ Tree, disk tabanlı depolama için tasarlanmış kendiliğinden dengeli çok yollu ağaçlardır. Temel motivasyon: disk erişimi RAM'den 100.000+ kat yavaştır — ağaç yüksekliğini düşürerek disk I/O sayısını minimize etmek gerekir. Her düğüm bir disk sayfası (4-16 KB) kadar veri tutarak yüzlerce dallanma sağlar → milyarlarca kayıt sadece 3-4 seviyeye sığar.

B+ Tree, B-Tree'nin veritabanı optimize edilmiş versiyonudur. İç düğümler sadece yol gösterici anahtar tutar (daha fazla dallanma), tüm veri yapraklardadır ve yapraklar bağlı liste ile birbirine bağlıdır (aralık sorguları için sıralı I/O). Bu yüzden MySQL, PostgreSQL, Oracle, SQLite gibi tüm modern veritabanları B+ Tree kullanır.

İndeksleme, veritabanı performansının en kritik konusudur. Doğru sütunlara doğru index'ler koymak, sorgu süresini saniyelerden milisaniyelere düşürebilir. Ama gereksiz index'ler yazma performansını olumsuz etkiler (her INSERT/UPDATE'de B+ Tree güncellenmeli). Denge: okuma ağırlıklı sorgularda index çok faydalı, yazma ağırlıklı iş yüklerinde dikkatli olunmalı.

Bölüm 6.7 özeti: B-Tree = disk-optimize çok yollu dengeli ağaç. Minimum derece t: düğüm t-1 ile 2t-1 anahtar tutar, çocuk sayısı = anahtar+1, yapraklar aynı derinlikte. Ekleme: yaprağa ekle, dolu ise split (medyan yukarı çıkar — ağaç yukarıdan büyür). Silme: yapraktan çıkar, underflow'da redistribute veya merge (ağaç aşağıdan küçülür). B+ Tree: veri sadece yapraklarda, iç düğümler sadece index, yapraklar bağlı liste → aralık sorguları O(logt n + k) — çok hızlı. Veritabanlarında PRIMARY KEY = clustered B+ Tree, CREATE INDEX = secondary B+ Tree. 16 KB sayfa ile 1.6 milyar kayıta 3 disk I/O ile erişim. Tüm modern RDBMS'ler (MySQL, PostgreSQL, Oracle, SQLite) B+ Tree kullanır.
← Veri Yapıları