---
title: 'Yedekleme Türleri'
source: 'https://academia.sh/tr/kurslar/veritabani-yonetimi/yedekleme-turleri'
course: 'İlişkisel Veritabanı Yönetimi'
language: tr
updated: '2026-08-17T18:08:55+00:00'
license: 'CC BY-SA 4.0'
---

# Yedekleme Türleri

Mantıksal, fiziksel ve artımlı yedeğin ölçülen maliyetleri: dosya boyutu ve alma süresi karşılaştırması, geri yüklenen kopyanın kaynakla eşitliğinin içerik karmasıyla kanıtlanması, su işareti tabanlı artımlı yedeğin sınırı.

Önceki ders satır düzeyi güvenliği kurarken bir noktayı açık bıraktı: bütün o koruma
çalışan sisteme aitti. Yedek dosyası politikasız bir kopyadır, ve daha temel bir şeydir —
veritabanının var olmayı sürdürmesinin tek güvencesidir. Disk arızası, yanlış yazılmış bir
`DELETE`, hatalı bir şema göçü ya da silinen bir dizin: hiçbiri yetki çizelgesiyle
önlenmez.

Bu ders yedeğin ne olduğunu değil, hangi biçimlerde alındığını ve her biçimin ne kadara
mal olduğunu ele alıyor. Kütüphane veritabanı üzerinde üç biçim ölçülecek ve geri
yüklenen kopyanın kaynakla eşit olduğu sözle değil sorguyla gösterilecek.

## Mantıksal ve Fiziksel Yedek

**Mantıksal yedek (logical backup)** veritabanının içeriğini yeniden üretecek deyimlerden
oluşur: tablo tanımları ve satırları anlatan `CREATE` ve `INSERT` deyimleri. Metin
dosyasıdır, okunabilir, düzenlenebilir ve farklı bir motora ya da farklı bir sürüme
yüklenebilir.

**Fiziksel yedek (physical backup)** veri dosyalarının kendisinin kopyasıdır. Sayfa
düzeyinde birebir kopyadır; anlamını yalnız aynı motor okur. Buna karşılık alınması
ucuzdur, çünkü hiçbir şey yeniden üretilmez — baytlar taşınır.

İkisi arasındaki seçim bir zevk meselesi değildir; ölçülebilir bir ödünleşimdir.

## Üç Biçimin Ölçümü

Aşağıdaki blok kütüphane veritabanını kurar, ardından dört yedekleme yolunu aynı veri
üzerinde ölçer. Süre ve boyut değerleri makineye, dosya sistemine ve sıkıştırma
kütüphanesine bağlıdır; sizde farklı sayılar çıkacaktır. Anlamlı olan mutlak değerler
değil, sütunlar arasındaki oranlardır.

```bash
cat > kur.sql <<'SQL'
CREATE TABLE sube(id INTEGER PRIMARY KEY, ad TEXT NOT NULL);
CREATE TABLE uye(id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sube_id INT NOT NULL);
CREATE TABLE kitap(id INTEGER PRIMARY KEY, baslik TEXT NOT NULL, sube_id INT NOT NULL);
CREATE TABLE odunc(id INTEGER PRIMARY KEY, kitap_id INT NOT NULL, uye_id INT NOT NULL,
                   sube_id INT NOT NULL, alis TEXT NOT NULL, iade TEXT);
INSERT INTO sube VALUES (1,'Merkez'),(2,'Sahil'),(3,'Tepe');
WITH RECURSIVE s(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM s WHERE n<20000)
INSERT INTO uye(id,ad,sube_id) SELECT n,'Uye-'||n,(n%3)+1 FROM s;
WITH RECURSIVE s(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM s WHERE n<50000)
INSERT INTO kitap(id,baslik,sube_id) SELECT n,'Kitap-'||n,(n%3)+1 FROM s;
WITH RECURSIVE s(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM s WHERE n<300000)
INSERT INTO odunc(id,kitap_id,uye_id,sube_id,alis,iade)
SELECT n,(n%50000)+1,(n%20000)+1,(n%3)+1,
       date('2023-01-01','+'||(n%900)||' day'),
       CASE WHEN n%4=0 THEN NULL ELSE date('2023-01-01','+'||((n%900)+14)||' day') END
FROM s;
CREATE INDEX odunc_uye ON odunc(uye_id);
CREATE INDEX odunc_sube_alis ON odunc(sube_id, alis);
SQL
rm -f kutuphane.db
sqlite3 kutuphane.db < kur.sql

cat > olc.mjs <<'EOF'
import { execSync } from "node:child_process";
import { statSync, rmSync } from "node:fs";

const olc = (ad, komut, cikti) => {
  rmSync(cikti, { force: true });
  const t0 = process.hrtime.bigint();
  execSync(komut);
  const ms = Number(process.hrtime.bigint() - t0) / 1e6;
  return { ad, ms, bayt: statSync(cikti).size };
};

const kaynak = statSync("kutuphane.db").size;
const olcumler = [
  olc("mantiksal (.dump)", "sqlite3 kutuphane.db .dump > mantiksal.sql", "mantiksal.sql"),
  olc("mantiksal + sikistirma", "sqlite3 kutuphane.db .dump | gzip -9 > mantiksal.sql.gz", "mantiksal.sql.gz"),
  olc("fiziksel (dosya kopyasi)", "cp kutuphane.db fiziksel.db", "fiziksel.db"),
  olc("fiziksel (tutarli anlik goruntu)", "sqlite3 kutuphane.db \"VACUUM INTO 'anlik.db'\"", "anlik.db"),
];

console.log("kaynak veritabani: " + kaynak.toLocaleString("tr-TR") + " bayt\n");
console.log("yedek bicimi                     |     bayt | kaynagin % | sure (ms)");
console.log("---------------------------------|----------|------------|----------");
for (const o of olcumler) {
  console.log(
    o.ad.padEnd(32) + " | " +
    String(o.bayt).padStart(8) + " | " +
    (100 * o.bayt / kaynak).toFixed(1).padStart(10) + " | " +
    o.ms.toFixed(0).padStart(8)
  );
}
EOF
node olc.mjs
```

```text
kaynak veritabani: 21.770.240 bayt

yedek bicimi                     |     bayt | kaynagin % | sure (ms)
---------------------------------|----------|------------|----------
mantiksal (.dump)                | 24561891 |      112.8 |      210
mantiksal + sikistirma           |  3983716 |       18.3 |      803
fiziksel (dosya kopyasi)         | 21770240 |      100.0 |        9
fiziksel (tutarli anlik goruntu) | 21770240 |      100.0 |       58
```

Dört satır dört ayrı karar anlatıyor.

Mantıksal yedek kaynaktan **büyük** çıktı. Sezgiye aykırı görünür ama nedeni açıktır:
sayıların ve tarihlerin ikili gösterimi metne çevrildiğinde şişer, her satır için ekleme
deyiminin metni yeniden yazılır. Buna karşılık dizinler dosyaya yazılmaz — yalnız
tanımları yazılır — bu da kısmen dengeler.

Sıkıştırılmış mantıksal yedek kaynağın beşte birinin altına indi. Metin yedeği son derece
sıkıştırılabilirdir, çünkü aynı deyim kalıbı satır sayısı kadar tekrarlanır. Bunun bedeli
süredir: sıkıştırma bu ölçümde yedek alma süresini birkaç katına çıkardı.

Dosya kopyası, mantıksal yedekten belirgin biçimde hızlıdır. Aradaki fark bir ölçek
sorusudur: mantıksal yedek her satırı okur, metne çevirir ve yazar; dosya kopyası yalnız
baytları taşır.

## Fiziksel Yedeğin Tutarlılık Sorunu

Yukarıdaki tabloda iki fiziksel satır var ve boyutları aynı. Aralarındaki fark boyutta
değil, güvenilirliktedir.

Çalışan bir veritabanının dosyasını doğrudan kopyalamak **tutarsız kopya** üretebilir.
Kopyalama sürerken motor dosyanın başına ve sonuna yazmayı sürdürür; kopyanın başı bir
ana, sonu başka bir ana aittir. Ortaya çıkan dosya hiçbir zaman var olmamış bir duruma
karşılık gelir ve açıldığında bozuk görünür — ya da daha kötüsü, açılır ve yanlış veri
verir.

Bu yüzden fiziksel yedek ya veritabanı durdurulmuşken alınır, ya da motorun kendi tutarlı
anlık görüntü aracıyla alınır. Tablodaki dördüncü satır bu araçtır: motor, tek bir tutarlı
noktadan okuyarak yeni bir dosya üretir. Ölçümde ham dosya kopyasının birkaç katı sürmesinin
nedeni budur; ödenen fark tutarlılığın bedelidir.

Aracın adı ve çağrılış biçimi motora göre değişir. Değişmeyen kural: **çalışan bir
veritabanının dosyası `cp` ile yedeklenmez.**

## Artımlı Yedek

Tam yedek her seferinde bütün veriyi taşır. Veritabanı büyüdükçe bu, hem sürede hem
saklama alanında dayanılmaz olur. **Artımlı yedek (incremental backup)**, son yedekten bu
yana değişen kısmı taşır.

Değişenin ne olduğunu belirlemenin en yalın yolu bir **su işaretidir (watermark)**: son
yedekte yer alan en büyük birincil anahtar değeri. Aşağıdaki blok tam yedeği alıyor,
sonra altı bin yeni ödünç kaydı ekliyor, ardından yalnız su işaretinden sonraki satırları
çıkarıyor ve iki dosyayı karşılaştırıyor.

Blok aynı zamanda geri yüklemeyi de yapıyor. **Geri yükleme yıkıcı bir işlemdir:** hedef
veritabanının üzerine yazar. Buradaki `rm -f` ve geri yükleme komutları yalnız bu blokta
üretilen geçici dosyalar üzerinde çalışır; gerçek bir kurulumda geri yükleme hedefi her
zaman yeni ve boş bir veritabanıdır, mevcut olan değil.

```bash
cat > kur.sql <<'SQL'
CREATE TABLE sube(id INTEGER PRIMARY KEY, ad TEXT NOT NULL);
CREATE TABLE uye(id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sube_id INT NOT NULL);
CREATE TABLE kitap(id INTEGER PRIMARY KEY, baslik TEXT NOT NULL, sube_id INT NOT NULL);
CREATE TABLE odunc(id INTEGER PRIMARY KEY, kitap_id INT NOT NULL, uye_id INT NOT NULL,
                   sube_id INT NOT NULL, alis TEXT NOT NULL, iade TEXT);
INSERT INTO sube VALUES (1,'Merkez'),(2,'Sahil'),(3,'Tepe');
WITH RECURSIVE s(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM s WHERE n<20000)
INSERT INTO uye(id,ad,sube_id) SELECT n,'Uye-'||n,(n%3)+1 FROM s;
WITH RECURSIVE s(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM s WHERE n<50000)
INSERT INTO kitap(id,baslik,sube_id) SELECT n,'Kitap-'||n,(n%3)+1 FROM s;
WITH RECURSIVE s(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM s WHERE n<300000)
INSERT INTO odunc(id,kitap_id,uye_id,sube_id,alis,iade)
SELECT n,(n%50000)+1,(n%20000)+1,(n%3)+1,
       date('2023-01-01','+'||(n%900)||' day'),
       CASE WHEN n%4=0 THEN NULL ELSE date('2023-01-01','+'||((n%900)+14)||' day') END
FROM s;
CREATE INDEX odunc_uye ON odunc(uye_id);
CREATE INDEX odunc_sube_alis ON odunc(sube_id, alis);
SQL
rm -f kutuphane.db geri.db tam.sql artimli.sql
sqlite3 kutuphane.db < kur.sql

sqlite3 kutuphane.db .dump > tam.sql

sqlite3 kutuphane.db "WITH RECURSIVE s(n) AS (SELECT 300001 UNION ALL SELECT n+1 FROM s WHERE n<306000)
INSERT INTO odunc(id,kitap_id,uye_id,sube_id,alis,iade)
SELECT n,(n%50000)+1,(n%20000)+1,(n%3)+1,date('2025-06-01','+'||(n%30)||' day'),NULL FROM s;"

sqlite3 kutuphane.db <<'ART' > artimli.sql
.mode insert odunc
SELECT * FROM odunc WHERE id > 300000 ORDER BY id;
ART

sqlite3 geri.db < tam.sql
sqlite3 geri.db < artimli.sql

echo "tam yedek     : $(wc -c < tam.sql | tr -d ' ') bayt"
echo "artimli yedek : $(wc -c < artimli.sql | tr -d ' ') bayt"
echo "kaynak satir  : $(sqlite3 kutuphane.db 'SELECT COUNT(*) FROM odunc;')"
echo "geri satir    : $(sqlite3 geri.db 'SELECT COUNT(*) FROM odunc;')"
echo "kaynak karma  : $(sqlite3 kutuphane.db '.sha3sum --schema --sha3-256')"
echo "geri karma    : $(sqlite3 geri.db '.sha3sum --schema --sha3-256')"
```

```text
tam yedek     : 24561891 bayt
artimli yedek : 381792 bayt
kaynak satir  : 306000
geri satir    : 306000
kaynak karma  : d97019d7e61335911bef2079db99030dd2f5e9938d4e24a769d85e56edef1eb6
geri karma    : d97019d7e61335911bef2079db99030dd2f5e9938d4e24a769d85e56edef1eb6
```

Artımlı yedek tam yedeğin yüzde iki kadarı. Günlük tam yedek yerine haftalık tam ve
günlük artımlı almanın nedeni bu orandır.

## Eşitliğin Kanıtı

Son iki satır bu dersin asıl noktasıdır. Karma değeri, veritabanının **içeriğinden**
hesaplanır: tablo adları, sütun tanımları ve satırların değerleri. Dosyanın fiziksel
düzeninden, boş sayfalarından ya da satırların diskteki sırasından etkilenmez.

İki karmanın eşit çıkması, geri yüklenen veritabanının kaynakla mantıksal olarak aynı
olduğunu gösterir. Satır saymak bunu göstermez — sayılar tutup değerler bozuk olabilir.
Gözle bakmak hiç göstermez.

Bu alışkanlığın adı vardır ve sonraki derslerin ikisi buna ayrılmıştır: bir yedeğin
geçerliliği, alındığı anda değil geri yüklendiği anda bilinir. "Yedek alıyoruz" cümlesi
bir güvence değildir; "yedeği geri yükleyip karmasını karşılaştırıyoruz" cümlesi bir
güvencedir.

## Su İşaretinin Kaçırdıkları

Yukarıdaki artımlı yedek yalnız **eklenen** satırları yakalar. Su işareti birincil anahtar
üzerinde çalışır ve birincil anahtar artan değerler üretir; dolayısıyla:

- Su işaretinden **önceki** bir satır güncellenmişse yakalanmaz.
- Su işaretinden önceki bir satır silinmişse yakalanmaz.
- Şema değişmişse yakalanmaz.

Kütüphane örneğinde bu üç boşluk somuttur. Bir kitabın iadesi, eski bir ödünç satırının
`iade` sütununu günceller — su işaretinden önceki bir satırdır ve artımlı yedeğe girmez.
Tam yedek ile artımlı yedeği birleştirerek geri yüklenen veritabanında o kitap hâlâ
ödünçte görünür.

Değişim zamanı taşıyan bir sütun eklemek güncellemeleri yakalar ama silmeleri yakalamaz —
silinen satırın değişim zamanı da silinmiştir. Silmeleri yakalamanın yolu, satırların
değil **işlemlerin** kaydını tutmaktır. Bu kayıt zaten vardır: motorun kalıcılık için
yazdığı günlük.

## Yedek Planının Üç Sayısı

Bir yedekleme planı üç sayıyla anlatılır.

**Kurtarma noktası hedefi (recovery point objective)**, kabul edilen en fazla veri kaybı
süresidir. Günde bir yedek alınıyorsa bu sayı yirmi dört saattir: arıza yedekten hemen
önce olursa bir günlük ödünç kaydı kaybolur.

**Kurtarma süresi hedefi (recovery time objective)**, sistemin yeniden çalışır hâle
gelmesi için kabul edilen en uzun süredir. Bu sayı yedeğin boyutuyla değil, geri yükleme
süresiyle ilgilidir — ve yukarıdaki ölçümde geri yükleme, yedek almadan uzun sürdü.
Mantıksal yedeğin ucuz saklanması, pahalı geri yüklenmesiyle ödenir.

**Saklama süresi (retention)**, yedeklerin ne kadar tutulacağıdır. Yalnız en son yedeği
tutmak tehlikelidir: bozulma fark edilmeden yedeklenmişse, tek yedek de bozuktur. Yedekler
farklı zamanlardan ve farklı ortamlardan oluşan bir küme olarak tutulur; en az bir kopyası
veritabanının bulunduğu makineden ayrı bir yerde durur.

## Özet

- Mantıksal yedek deyimlerden oluşur, taşınabilirdir ve iyi sıkışır; fiziksel yedek
  dosyaların kopyasıdır, alınması hızlıdır ve aynı motora bağlıdır.
- Mantıksal yedek kaynaktan büyük olabilir; sıkıştırma boyutu birkaç kata düşürür,
  bedeli süredir.
- Çalışan bir veritabanının dosyası doğrudan kopyalanamaz; tutarlı fiziksel yedek ya
  durdurulmuş sistemden ya motorun anlık görüntü aracıyla alınır.
- Artımlı yedek tam yedeğin küçük bir bölümü kadar yer tutar; su işareti tabanlı artımlı
  yedek eklemeleri yakalar, güncelleme ve silmeleri kaçırır.
- Geri yüklenen kopyanın kaynakla eşitliği içerik karmasıyla kanıtlanır; satır saymak
  yeterli değildir.
- Yedek planı kurtarma noktası hedefi, kurtarma süresi hedefi ve saklama süresiyle
  tanımlanır.

## Sonraki Adım

Su işareti tabanlı artımlı yedeğin üç boşluğu — güncellemeler, silmeler ve şema
değişiklikleri — hepsi aynı nedenden kaynaklanıyordu: satırların son hâline bakmak,
aralarında ne olduğunu anlatmaz. Aradaki her değişikliği sırayla kaydeden bir kaynak
zaten var; motorun kalıcılık için yazdığı günlük. Sonraki ders bu günlüğün yedekle
birlikte kullanılmasını ele alıyor: bir tam yedeğin üzerine günlük kayıtlarını belirli bir
ana kadar uygulayarak veritabanını dün öğlen on birdeki hâline döndürmek.
