---
title: 'Parçalama Kalıpları'
source: 'https://academia.sh/tr/kurslar/veritabani-yonetimi/parcalama-kaliplari'
course: 'İlişkisel Veritabanı Yönetimi'
language: tr
updated: '2026-08-17T18:08:57+00:00'
license: 'CC BY-SA 4.0'
---

# Parçalama Kalıpları

Bölümlerin ayrı makinelere dağıtılması, parça anahtarının uygulamaya dayattığı sınırlar, çapraz parça sorgusunun kuyruk gecikmesi, parçalar arası birleştirme ve benzersizlik sorunu ile yeniden dengelemede taşınan veri miktarı.

Önceki ders bir tabloyu bölümlere ayırdı ve bütün bölümler aynı veritabanının içindeydi.
Bölümleri ayrı makinelere dağıtmak, aynı fikrin bir adım ötesidir ve o adımda nitelik
değişir.

**Parçalama (sharding)**, verinin yatay olarak bölünüp birden çok bağımsız veritabanı
örneğine dağıtılmasıdır. Her parça kendi süreçlerini, kendi tampon havuzunu, kendi
günlüğünü ve kendi kilit yöneticisini taşır. Motor Mimarisi konusunda kurulan her yapı
parça başına bir kez vardır ve parçalar birbirinin varlığından haberli değildir. Kazanç
budur: yazma yükü, bellek ve disk gerçekten bölünür. Bedel de budur: bir tablonun tek
bir motor içinde bedelsiz sayılan üç yeteneği — birleştirme, benzersizlik ve işlem —
parçalar arasında bedelsiz olmaktan çıkar.

Bu ders o üç bedeli sayar. Ölçümler `node` ile kurulan modellerdir; gerçek bir dağıtık
veritabanı değildirler. Modelin sayabildiği şey ilişkilerdir — hangi seçim hangi maliyeti
kaç kat büyütür — mutlak değerler değil.

## Parça Anahtarı Uygulamaya Ne Dayatır

**Parça anahtarı (shard key)**, bir satırın hangi parçaya düşeceğini belirleyen sütundur.
Kütüphane verisinde iki aday vardır ve seçim, hangi sorgunun ucuz olacağını belirler.

Üye kimliğine göre parçalanan bir kurulumda bir üyenin bütün ödünç kayıtları tek bir
parçadadır. "Bu üyenin açık ödünçleri" sorusu tek parçaya gider; sorgu, tek makineli bir
kurulumdaki sorgudan farksızdır. Aynı kurulumda "bu kitabı kimler ödünç aldı" sorusunun
yanıtı bütün parçalara dağılmıştır.

Kitap kimliğine göre parçalanan kurulumda ilişki tersine döner. Hangi seçimin doğru
olduğu veriden değil, **iş yükünün soru dağılımından** çıkar: en sık sorulan ve en düşük
gecikme beklenen soru hangi anahtarı süzüyorsa parça anahtarı odur.

Bu karar, tek makineli bir kurulumda geri alınabilir bir dizin kararına benzemez. Dizin
kaldırılıp yeniden kurulabilir; parça anahtarı değiştirmek verinin tamamının taşınması
demektir. Parçalamanın uygulamaya ilk dayattığı şey budur: **sorgu biçimleri veri düzenini
belirler ve sonradan değiştirilmesi pahalıdır.**

## Çapraz Parça Sorgusu

Parça anahtarını süzmeyen bir sorgu bütün parçalara gönderilir, her parçadan kısmi sonuç
alınır ve eşgüdümcü bunları birleştirir. Bu kalıba **dağıt–topla (scatter–gather)** denir
ve maliyeti sezgiye aykırıdır: yapılan toplam iş aynı kalsa bile yanıt süresi bozulur,
çünkü sorgu **en yavaş parçayı** beklemek zorundadır.

```sh
cat > capraz.mjs <<'JS'
// Model: 8 parcaya dagitilmis odunc kayitlarinda sorgu turlerinin dokundugu parca sayisi
// ve yanit suresi. Gercek bir dagitik veritabani degil; sayilan sey dokunulan parca
// sayisi ile kuyruk gecikmesi arasindaki iliskidir.
const PARCA = 8, SORGU = 20000;
// Yinelenebilir sozde rastgele uretec (dogrusal kongruansiyel).
let durum = 20240728;
const rastgele = () => (durum = (durum * 1103515245 + 12345) % 2147483648) / 2147483648;

// Bir parcanin yanit suresi: 2 ms taban + agirlikli kuyruk. Yuzde bir olasilikla yavas.
function parcaSuresi() {
  const r = rastgele();
  return r < 0.99 ? 2 + 3 * r : 40 + 60 * r;
}
function olc(dokunulanParca) {
  const sureler = [];
  for (let i = 0; i < SORGU; i++) {
    let enYavas = 0;
    for (let p = 0; p < dokunulanParca; p++) enYavas = Math.max(enYavas, parcaSuresi());
    sureler.push(enYavas + 1);            // 1 ms eşgüdüm payı
  }
  sureler.sort((a, b) => a - b);
  const yuzde = (q) => sureler[Math.floor(SORGU * q)];
  return { orta: yuzde(0.5), p95: yuzde(0.95), p99: yuzde(0.99), enKotu: sureler[SORGU - 1] };
}
console.log('dokunulan parça   ortanca      %95      %99   en kötü');
for (const d of [1, 2, 4, 8]) {
  const s = olc(d);
  console.log(String(d).padStart(14),
              s.orta.toFixed(1).padStart(9), s.p95.toFixed(1).padStart(8),
              s.p99.toFixed(1).padStart(8), s.enKotu.toFixed(1).padStart(9));
}
console.log('\n— sorgu karışımı: parça anahtarı var mı —');
const karisim = [
  ['üyenin ödünçleri (parça anahtarı var)', 1],
  ['kitabın ödünç geçmişi (anahtar yok)',   PARCA],
  ['aylık rapor (anahtar yok)',             PARCA],
];
for (const [ad, d] of karisim) {
  const s = olc(d);
  console.log(ad.padEnd(38), 'parça', String(d).padStart(2),
              '| ortanca', s.orta.toFixed(1).padStart(5),
              '| %99', s.p99.toFixed(1).padStart(6), 'ms');
}
JS
node capraz.mjs
```

```
dokunulan parça   ortanca      %95      %99   en kötü
             1       4.5      5.9      6.0     101.0
             2       5.1      5.9    100.6     101.0
             4       5.5      6.0    100.8     101.0
             8       5.8    100.5    100.9     101.0

— sorgu karışımı: parça anahtarı var mı —
üyenin ödünçleri (parça anahtarı var)  parça  1 | ortanca   4.5 | %99    6.0 ms
kitabın ödünç geçmişi (anahtar yok)    parça  8 | ortanca   5.8 | %99  100.9 ms
aylık rapor (anahtar yok)              parça  8 | ortanca   5.8 | %99  100.9 ms
```

Modelde her parçanın yüzde bir olasılıkla yavaş yanıt verdiği varsayılmıştır. Ortanca
süre bu varsayımdan neredeyse etkilenmiyor: tek parçada 4,5 ms, sekiz parçada 5,8 ms.
Kuyruk ise çöküyor. Tek parçada yüzde 99'luk dilim 6,0 ms iken sekiz parçada 100,9 ms
oldu — on yedi kat.

Aritmetiği doğrudandır. Tek bir parçanın yavaş olma olasılığı yüzde bir ise, sekiz
parçadan **en az birinin** yavaş olma olasılığı $1 - 0{,}99^8 \approx 0{,}077$, yani
yüzde 7,7. Dağıt–topla, her parçanın nadir kusurunu sorgunun sık kusuruna çevirir.

Buradan parçalamanın en çok yanlış anlaşılan yanı çıkar: parçalama **çıktıyı (throughput)**
büyütür, tek bir sorgunun gecikmesini küçültmez. Ortalama sürelere bakan bir ölçüm bu
bozulmayı hiç görmez; görülmesi için kuyruk dilimlerine bakmak gerekir.

## Birleştirme, Benzersizlik ve İşlem

Üç yetenek parça sınırında niteliğini değiştirir.

**Birleştirme.** Üye kimliğine göre parçalanmış ödünç kayıtları, aynı anahtara göre
parçalanmış üye tablosuyla parça içinde birleştirilebilir; iki tablonun ilgili satırları
aynı makinededir. Buna **birlikte yerleştirme (co-location)** denir ve parçalı bir
tasarımda birleştirmenin ucuz kalmasının tek yoludur. Kitap tablosu ise ödünç kayıtlarıyla
birlikte yerleştirilemez, çünkü ödünç kaydı iki farklı anahtara birden ait olamaz. Yaygın
çözüm, küçük ve seyrek değişen tabloların her parçaya **kopyalanmasıdır**; kütüphane
örneğinde şube listesi böyle bir tablodur.

**Benzersizlik.** Tek bir motorda benzersizlik kısıtı bir dizinle uygulanır. Parçalar
arasında böyle bir dizin yoktur: her parça yalnız kendi satırlarını görür, dolayısıyla
yalnız **parça içinde** benzersizlik verebilir. Genel benzersizlik gerektiren bir alan —
üyenin e-posta adresi gibi — ya parça anahtarı olur, ya ayrı bir arama tablosunda tutulur.
Otomatik artan kimlikler de aynı nedenle çalışmaz; parçalı kurulumlarda kimlikler
merkezden değil, parça numarasını içeren ya da çakışma olasılığı ihmal edilebilir olacak
kadar geniş bir üreteçten alınır.

**İşlem.** ACID Özellikleri dersinde tanımlanan atomiklik tek bir motorun günlüğüne
dayanır. İki parçaya birden yazan bir işlem iki ayrı günlüğe yazar ve ikisinin birlikte
kesinleşmesi ayrı bir protokol gerektirir: eşgüdümcü önce bütün parçalara hazırlanma
buyruğu verir, hepsinden onay alırsa kesinleştirir. Bu protokolün bedeli ek gidiş
dönüşler değil, **askıda kalma** olasılığıdır — eşgüdümcü hazırlık ile kesinleştirme
arasında düşerse parçalar kilitlerini tutarak bekler. Parçalı tasarımın altın kuralı bu
yüzden şudur: bir işlem tek bir parçanın içinde kalmalıdır. Kalamıyorsa, tasarım ya parça
anahtarını ya işlem sınırını yanlış seçmiştir.

## Yeniden Dengeleme

Parça sayısı sabit kalmaz. Yeni bir parça eklendiğinde anahtar–parça eşlemesi değişir ve
değişen her eşleme, veri taşınması demektir. Taşınan miktar eşlemenin nasıl kurulduğuna
bağlıdır ve bu hesaplanabilir.

```sh
cat > dengele.mjs <<'JS'
// Model: parca sayisi degistiginde tasinmasi gereken satir orani. Gercek bir yeniden
// dengeleme yordami degil; sayilan sey yalnizca eslemenin tasima maliyetine etkisidir.
const UYE = 120000, KOVA = 4096;
const M = 2654435761n;
const karma = (x) => Number(((BigInt(x) * M) % 4294967296n) >> 8n);

// Uye basina odunc sayisi: az sayida uye cok odunc alir.
const uye = [];
{
  let toplam = 0;
  const agirlik = [];
  for (let i = 1; i <= UYE; i++) { const a = 1 / Math.pow(i, 0.8); agirlik.push(a); toplam += a; }
  for (let i = 0; i < UYE; i++)
    uye.push({ id: i + 1, odunc: Math.max(1, Math.round(agirlik[i] / toplam * 2000000)) });
}
const toplamSatir = uye.reduce((t, u) => t + u.odunc, 0);

function modTasima(eski, yeni) {
  let tasinan = 0;
  for (const u of uye) if (karma(u.id) % eski !== karma(u.id) % yeni) tasinan += u.odunc;
  return tasinan;
}
// Sanal kova: anahtar sabit sayida kovaya duser, kovalar parcalara atanir.
function kovaAtama(P) {
  const atama = new Array(KOVA);
  for (let b = 0; b < KOVA; b++) atama[b] = b % P;
  return atama;
}
function kovaTasima(eski, yeni) {
  const eskiAtama = kovaAtama(eski);
  const hedef = Math.floor(KOVA / yeni);
  const sayac = new Array(yeni).fill(0);
  const yeniAtama = new Array(KOVA).fill(-1);
  for (let b = 0; b < KOVA; b++) {                 // once yerinde kalabilecekler
    const p = eskiAtama[b];
    if (p < yeni && sayac[p] < hedef) { yeniAtama[b] = p; sayac[p]++; }
  }
  let p = 0;
  for (let b = 0; b < KOVA; b++) {                 // bosta kalanlar aza dogru dagitilir
    if (yeniAtama[b] !== -1) continue;
    while (p < yeni - 1 && sayac[p] >= hedef) p++;
    yeniAtama[b] = p; sayac[p]++;
  }
  let tasinan = 0;
  for (const u of uye) {
    const b = karma(u.id) % KOVA;
    if (eskiAtama[b] !== yeniAtama[b]) tasinan += u.odunc;
  }
  return tasinan;
}
console.log('modeldeki toplam ödünç:', toplamSatir);
console.log('geçiş        doğrudan bölme        sanal kova');
for (const [e, y] of [[8, 9], [8, 12], [8, 16]]) {
  const a = modTasima(e, y), b = kovaTasima(e, y);
  const yuzde = (x) => (100 * x / toplamSatir).toFixed(1) + '%';
  console.log(`${e} → ${y}`.padEnd(12),
              (a.toLocaleString('tr-TR') + ' (' + yuzde(a) + ')').padStart(21),
              (b.toLocaleString('tr-TR') + ' (' + yuzde(b) + ')').padStart(18));
}
JS
node dengele.mjs
```

```
modeldeki toplam ödünç: 2001046
geçiş        doğrudan bölme        sanal kova
8 → 9            1.793.865 (89.6%)    228.270 (11.4%)
8 → 12           1.337.553 (66.8%)    675.360 (33.8%)
8 → 16           1.006.912 (50.3%)    982.390 (49.1%)
```

Doğrudan bölme — anahtarın karmasını parça sayısına bölüp kalanı almak — sekizden dokuza
geçişte kayıtların yüzde 89,6'sını taşıttı. Tek bir parça eklemek için verinin neredeyse
tamamının yerinden oynaması gerekiyor, çünkü bölen değiştiğinde kalan da neredeyse her
anahtar için değişir.

**Sanal kova (virtual bucket)** yaklaşımı araya bir katman koyar: anahtar önce sabit
sayıda kovaya (burada 4.096) düşürülür, kovalar parçalara atanır. Parça sayısı
değiştiğinde anahtar–kova eşlemesi hiç değişmez; yalnız kova–parça ataması güncellenir ve
yalnız yeni parçaya devredilen kovaların verisi taşınır. Sekizden dokuza geçişte taşınan
oran yüzde 11,4 oldu — kuramsal alt sınır olan 1/9 ≈ yüzde 11,1'e çok yakın.

Üçüncü satır bir uyarı taşır. Sekizden on altıya geçişte iki yöntem eşitleniyor (yüzde
50,3'e karşı yüzde 49,1), çünkü parça sayısını ikiye katlamak doğrudan bölmenin en şanslı
durumudur: her parça tam ikiye ayrılır. Bu, ikiye katlamayı geçerli bir büyüme
stratejisi yapar — ama ancak ikiye katlanabildiği sürece. Kaynak planlaması buna
zorlandığında maliyet, gerekmeyen kapasitenin peşinen alınmasıdır.

Taşınan oranın kendisi de son bedel değildir. Taşıma sırasında iki kopya bir süre birlikte
yaşar, okumalar iki yerden yanıtlanabilir olmalıdır ve yazmalar taşınmakta olan kovalar
için ya durdurulur ya iki yere birden yazılır. Bu yüzden yeniden dengeleme, parça
sayısından çok, taşımanın **kesintisiz yapılıp yapılamadığıyla** ölçülen bir yetenektir.

## Parçalamaya Ne Zaman Gerek Yoktur

Parçalama, sayılan bedellerin hepsini uygulama koduna taşır. Bu yüzden son soru, ondan
kaçınmanın yollarının tükenip tükenmediğidir. Bu kursta ölçülen üç yol çoğu zaman daha
önce gelir: doğru dizinler okuma maliyetini büyüklük sırasıyla düşürdü, bölümleme eski
verinin kaldırılmasını sabit maliyete indirdi, okuma yükü ise çoğaltmayla dağıtılabilir.

Parçalamayı gerçekten zorunlu kılan tek etken **yazma** yüküdür ve o da tek bir motorun
günlük ile denetim noktası kapasitesi aşıldığında. Karar bu ölçüyle verilir; "tablo büyük"
ölçüsüyle değil.

## Özet

- Parçalama veriyi bağımsız veritabanı örneklerine dağıtır; parça anahtarı hangi sorgunun
  tek parçada kalacağını belirler ve sonradan değiştirilmesi verinin tamamının taşınması
  demektir.
- Dağıt–topla kalıbı ortanca süreyi az etkiler, kuyruğu bozar: modelde tek parçada 6,0 ms
  olan yüzde 99'luk dilim sekiz parçada 100,9 ms oldu.
- Birleştirme ancak birlikte yerleştirilmiş tablolarda ucuz kalır; benzersizlik yalnız parça
  içinde uygulanabilir; iki parçaya yazan işlem ayrı bir protokol ve askıda kalma riski
  getirir.
- Doğrudan bölmede sekizden dokuz parçaya geçiş kayıtların yüzde 89,6'sını taşıttı; sanal
  kova katmanıyla aynı geçiş yüzde 11,4'e indi.
- Parçalamayı zorunlu kılan etken yazma yükünün tek motorun kapasitesini aşmasıdır; dizin,
  bölümleme ve çoğaltma bu eşiğe kadar daha ucuz yollardır.

## Sonraki Adım

Bu konu verinin nasıl düzenlendiğini ve hangi yollardan okunduğunu tamamladı: dizin
türleri, sütun sırası, kapsama, bakım, bölümleme ve parçalama. Motor Mimarisi konusuyla
birlikte artık verinin nerede durduğu ve nasıl bulunduğu kurulmuş durumda — sistem
çalışır hâldedir. Çalışır olmak ile işletiliyor olmak ayrı şeylerdir. Sonraki konu bu
ayrımla açılır ve ilk sorusu en eskisidir: bu veriye kim erişebilir ve ne yapabilir? Ödünç
masasındaki uygulamanın ödünç kaydı açması gerekir, üye kaydını silmesi gerekmez; bu
ayrımın yetki düzeyinde nasıl kurulacağı sonraki dersin konusudur.
