Veritabanı Yedeği için mysqldump Sorgu Örnekleri

Veritabanı yönetiminde en kritik konulardan biri düzenli ve güvenilir yedekleme yapmaktır. Production ortamında bir şeyler ters gittiğinde, elinizdeki tek can simidi o yedek dosyasıdır. MySQL ve MariaDB dünyasında mysqldump aracı, yıllardır sysadmin’lerin vazgeçilmezi olmaya devam ediyor. Basit görünse de, parametrelerini ve kullanım senaryolarını iyi bilmeden yapılan yedekler sizi zor anında hayal kırıklığına uğratabilir. Bu yazıda gerçek dünya senaryolarıyla mysqldump kullanımını tüm detaylarıyla ele alacağız.

mysqldump Nedir ve Nasıl Çalışır?

mysqldump MySQL ve MariaDB ile birlikte gelen bir komut satırı yardımcı programıdır. Veritabanı yapısını ve verilerini SQL formatında dışa aktarır. Oluşturduğu dosya, içinde CREATE TABLE, INSERT INTO gibi SQL ifadelerini barındıran düz metin bir dosyadır. Bu dosyayı herhangi bir MySQL/MariaDB sunucusuna geri yükleyebilirsiniz.

Çalışma prensibi şudur: mysqldump veritabanına bağlanır, tablo yapılarını ve verileri okur, bunları SQL komutlarına çevirir ve belirttiğiniz dosyaya yazar. Bu süreçte tablolar geçici olarak kilitlenebilir, bu yüzden büyük production veritabanlarında dikkatli olmak gerekir.

Temel Kullanım ve Bağlantı Parametreleri

En basit haliyle bir veritabanını yedeklemek için:

mysqldump -u kullanici_adi -p veritabani_adi > yedek.sql

Bu komutu çalıştırdığınızda sistem sizden şifre isteyecektir. Production ortamında otomatik yedekleme scriptleri için şifreyi interaktif girmek pratik değildir. Bu durumda birkaç seçeneğiniz var.

Seçenek 1: Şifreyi komut satırına yazmak (güvensiz)

mysqldump -u root -pSifreniz veritabani_adi > yedek.sql

Bu yöntemi kesinlikle tavsiye etmiyorum çünkü şifre ps aux çıktısında görünür.

Seçenek 2: .my.cnf dosyası kullanmak (önerilen)

# /root/.my.cnf dosyası oluşturun
cat > /root/.my.cnf << EOF
[mysqldump]
user=root
password=GucluSifreniz

[mysql]
user=root
password=GucluSifreniz
EOF

# Dosya izinlerini düzeltin
chmod 600 /root/.my.cnf

Bu ayarı yaptıktan sonra şifre parametresi olmadan çalıştırabilirsiniz:

mysqldump veritabani_adi > yedek.sql

Sık Kullanılan Parametreler

mysqldump onlarca parametre sunar. Günlük işlerde en çok işinize yarayacakları şöyle sıralayabilirim:

  • -u: Kullanıcı adını belirtir
  • -p: Şifre istemek için kullanılır
  • -h: Host adresini belirtir, varsayılan localhost’tur
  • -P: Port numarasını belirtir, varsayılan 3306’dır
  • –all-databases: Tüm veritabanlarını yedekler
  • –databases: Birden fazla veritabanı belirtmek için kullanılır
  • –single-transaction: InnoDB tablolar için kilitlemesiz yedek alır
  • –lock-tables: MyISAM tablolar için tablo kilitleme yapar
  • –no-data: Sadece tablo yapısını alır, veri almaz
  • –no-create-info: Sadece veriyi alır, tablo yapısını almaz
  • –where: Belirli koşulla filtrelenmiş veri alır
  • –compress: Sunucu ile istemci arasındaki veriyi sıkıştırır
  • –routines: Stored procedure ve function’ları dahil eder
  • –triggers: Trigger’ları dahil eder, varsayılan olarak aktiftir
  • –events: Event scheduler’daki event’leri dahil eder
  • –hex-blob: BLOB alanlarını hexadecimal formatında yazar
  • –add-drop-table: Her CREATE TABLE’dan önce DROP TABLE ekler
  • –skip-add-drop-table: DROP TABLE ifadelerini eklemez
  • –extended-insert: Daha hızlı ve kompakt INSERT ifadeleri kullanır
  • –quick: Büyük tablolar için satır satır okuma yapar, bellek tasarrufu sağlar

Senaryo 1: Tek Veritabanı Yedeği

En yaygın kullanım senaryosu tek bir veritabanını yedeklemektir. Bir e-ticaret sitesinin veritabanını yedeklediğimizi düşünelim:

mysqldump 
  -u backup_user 
  -p 
  --single-transaction 
  --routines 
  --triggers 
  --events 
  --hex-blob 
  --quick 
  eticaret_db > /backup/eticaret_db_$(date +%Y%m%d_%H%M%S).sql

Burada --single-transaction parametresine dikkat edin. Bu parametre InnoDB motorunu kullanan tablolarda yedeği bir transaction içinde alır ve tabloları kilitlemez. Production ortamında kullanıcılar veritabanına yazmaya devam ederken yedek alabilirsiniz. Ancak bu sadece InnoDB için geçerlidir, MyISAM tablolarınız varsa --lock-tables kullanmanız gerekir.

Senaryo 2: Tüm Veritabanlarını Yedeklemek

Sunucuda birden fazla veritabanı varsa hepsini tek seferde yedeklemek için:

mysqldump 
  -u root 
  --all-databases 
  --single-transaction 
  --routines 
  --triggers 
  --events 
  --master-data=2 
  --flush-logs 
  > /backup/full_backup_$(date +%Y%m%d_%H%M%S).sql

--master-data=2 parametresi yorum satırı olarak binary log pozisyonunu dosyaya yazar. Bu, replikasyon kurulumlarında veya point-in-time recovery için çok işinize yarayacak bir bilgidir. --flush-logs ise yedek başlamadan önce binary logları döndürür.

Birden fazla ama belirli veritabanlarını yedeklemek için:

mysqldump 
  -u root 
  --databases musteri_db siparis_db urun_db 
  --single-transaction 
  > /backup/secili_veritabanlari_$(date +%Y%m%d).sql

Senaryo 3: Sadece Yapı veya Sadece Veri Almak

Bazen tablonun sadece yapısına ihtiyacınız olur, bazen de sadece veriye. Örneğin bir test ortamı kurarken production veritabanının yapısını kopyalamak isteyebilirsiniz:

# Sadece tablo yapısını al (veri olmadan)
mysqldump 
  -u root 
  --no-data 
  --routines 
  --triggers 
  production_db > /tmp/yapi_sadece.sql

# Test veritabanına uygula
mysql -u root test_db < /tmp/yapi_sadece.sql

Tersine, mevcut bir yapıya yeni veri yüklemek için:

# Sadece veriyi al
mysqldump 
  -u root 
  --no-create-info 
  --skip-add-drop-table 
  production_db > /tmp/veri_sadece.sql

Senaryo 4: Belirli Tabloları Yedeklemek

Bazen tüm veritabanını değil, sadece belirli tabloları yedeklemeniz gerekir. Log tablolarını veya büyük geçmiş tablolarını atlamak isteyebilirsiniz:

# Belirli tabloları yedekle
mysqldump 
  -u root 
  musteri_db 
  musteriler siparisler urunler 
  --single-transaction 
  > /backup/onemli_tablolar.sql

Büyük log tablolarını atlayarak yedek almak için --ignore-table kullanabilirsiniz:

mysqldump 
  -u root 
  --single-transaction 
  --ignore-table=musteri_db.islem_loglari 
  --ignore-table=musteri_db.hata_loglari 
  musteri_db > /backup/musteri_db_noslog.sql

Senaryo 5: Koşullu Veri Yedekleme

--where parametresi ile belirli koşulları sağlayan kayıtları yedekleyebilirsiniz. Bu özellikle büyük tablolarda belirli bir tarih aralığını veya belirli kayıtları almanız gerektiğinde çok işe yarar:

# Son 30 günün siparişlerini al
mysqldump 
  -u root 
  --single-transaction 
  --where="created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)" 
  eticaret_db siparisler 
  > /backup/son30gun_siparisler.sql

# Belirli bir müşterinin verilerini al
mysqldump 
  -u root 
  --where="musteri_id = 12345" 
  eticaret_db siparisler siparis_detaylari 
  > /tmp/musteri_12345_verileri.sql

Bu senaryoyu gerçek hayatta sıkça kullanıyorum. Örneğin bir müşteri “benim verilerimi sil” talep ettiğinde, silmeden önce o müşteriye ait tüm verileri arşivlemem gerekiyor. --where parametresi burada hayat kurtarıcı oluyor.

Sıkıştırılmış Yedek Almak

Büyük veritabanlarında yedek dosyaları çok yer kaplayabilir. Doğrudan sıkıştırarak yedek almak disk alanından önemli ölçüde tasarruf sağlar:

# gzip ile sıkıştır
mysqldump 
  -u root 
  --single-transaction 
  --quick 
  buyuk_veritabani | gzip -9 > /backup/buyuk_db_$(date +%Y%m%d).sql.gz

# bzip2 ile daha iyi sıkıştırma (daha yavaş)
mysqldump 
  -u root 
  --single-transaction 
  buyuk_veritabani | bzip2 > /backup/buyuk_db_$(date +%Y%m%d).sql.bz2

# xz ile en iyi sıkıştırma (en yavaş)
mysqldump 
  -u root 
  --single-transaction 
  buyuk_veritabani | xz > /backup/buyuk_db_$(date +%Y%m%d).sql.xz

Gzip genellikle en iyi denge noktasıdır. Ortalama bir veritabanı için %70-80 oranında sıkıştırma sağlayabilirsiniz.

Otomatik Yedekleme Script’i

İşte production ortamında kullandığım, biraz geliştirilmiş bir yedekleme scripti:

#!/bin/bash
# /usr/local/bin/db_backup.sh

# Konfigürasyon
BACKUP_DIR="/backup/mysql"
RETENTION_DAYS=7
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/mysql_backup.log"
MYSQL_USER="backup_user"

# Bildirim fonksiyonu
log_message() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

# Backup dizinini oluştur
mkdir -p "$BACKUP_DIR"

log_message "Yedekleme basliyor..."

# Tüm veritabanlarını listele (system veritabanları hariç)
DATABASES=$(mysql -u "$MYSQL_USER" -e "SHOW DATABASES;" | 
  grep -Ev "^(Database|information_schema|performance_schema|sys|mysql)$")

# Her veritabanı için ayrı yedek al
for DB in $DATABASES; do
    log_message "Yedekleniyor: $DB"
    
    OUTPUT_FILE="$BACKUP_DIR/${DB}_${DATE}.sql.gz"
    
    if mysqldump 
        -u "$MYSQL_USER" 
        --single-transaction 
        --routines 
        --triggers 
        --events 
        --hex-blob 
        --quick 
        "$DB" | gzip -6 > "$OUTPUT_FILE"; then
        
        SIZE=$(du -sh "$OUTPUT_FILE" | cut -f1)
        log_message "Basarili: $DB -> $OUTPUT_FILE ($SIZE)"
    else
        log_message "HATA: $DB yedeklenemedi!"
        # Hata durumunda e-posta gönder
        echo "HATA: $DB veritabani yedeklenemedi! Sunucu: $(hostname)" | 
          mail -s "MySQL Yedekleme Hatasi" [email protected]
    fi
done

# Eski yedekleri temizle
log_message "Eski yedekler temizleniyor (${RETENTION_DAYS} gunden eski)..."
find "$BACKUP_DIR" -name "*.sql.gz" -mtime "+$RETENTION_DAYS" -delete

log_message "Yedekleme tamamlandi."

Bu scripti crontab’a eklemek için:

# Crontab'ı düzenle
crontab -e

# Her gece 02:00'de çalıştır
0 2 * * * /usr/local/bin/db_backup.sh

Yedeği Geri Yüklemek

Yedeği almak kadar önemli olan bir konu da yedeği düzgün geri yükleyebilmektir. Düzenli aralıklarla restore testleri yapmanızı kesinlikle tavsiye ederim.

# Düz SQL dosyasını geri yükle
mysql -u root -p veritabani_adi < yedek.sql

# Gzip'li yedeği doğrudan geri yükle
gunzip -c yedek.sql.gz | mysql -u root -p veritabani_adi

# Yeni bir veritabanı oluşturup geri yükle
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS yeni_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql -u root -p yeni_db < yedek.sql

# --all-databases ile alınan yedeği geri yükle
mysql -u root -p < full_backup.sql

Uzak Sunucudan Yedek Almak

Bazen yerel sunucudan değil, uzaktaki bir veritabanı sunucusundan yedek almanız gerekebilir:

# Uzak sunucudan yedek al ve yerel diske kaydet
mysqldump 
  -h 192.168.1.100 
  -P 3306 
  -u backup_user 
  -p 
  --single-transaction 
  production_db | gzip > /local/backup/remote_backup_$(date +%Y%m%d).sql.gz

# SSH tüneli üzerinden güvenli bağlantı
ssh -L 3307:localhost:3306 user@uzak_sunucu -N &
mysqldump 
  -h 127.0.0.1 
  -P 3307 
  -u backup_user 
  -p 
  production_db > /backup/guvenli_yedek.sql

Yedekleme Kullanıcısı Oluşturmak

Root kullanıcısıyla yedekleme yapmak güvenlik açısından iyi bir pratik değildir. Sadece gerekli yetkilere sahip bir yedekleme kullanıcısı oluşturmalısınız:

# MySQL'e bağlan ve yedekleme kullanıcısı oluştur
mysql -u root -p << EOF
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'GucluBirSifre123!';
GRANT SELECT, SHOW VIEW, RELOAD, REPLICATION CLIENT, EVENT, TRIGGER ON *.* TO 'backup_user'@'localhost';
GRANT LOCK TABLES ON *.* TO 'backup_user'@'localhost';
FLUSH PRIVILEGES;
EOF

Bu kullanıcı sadece okuma ve yedekleme işlemleri için gerekli yetkilere sahip olacak, verileri değiştiremeyecektir.

Yedek Dosyasını Doğrulamak

Aldığınız yedeğin sağlıklı olup olmadığını kontrol etmek için birkaç yöntem:

# Dosya boyutunu kontrol et (0 byte ise bir şeyler yanlış)
ls -lh /backup/yedek.sql.gz

# Gzip dosyasının bütünlüğünü kontrol et
gunzip -t /backup/yedek.sql.gz && echo "Dosya saglikli" || echo "HATA: Dosya bozuk"

# SQL dosyasının başına bak
gunzip -c /backup/yedek.sql.gz | head -50

# Satır sayısını kontrol et
gunzip -c /backup/yedek.sql.gz | wc -l

# mysqldump'ın sonuna eklediği tamamlanma yorumunu kontrol et
gunzip -c /backup/yedek.sql.gz | tail -5

Sağlıklı bir mysqldump çıktısının sonunda şuna benzer bir satır görmelisiniz:

-- Dump completed on 2024-01-15 02:05:33

Bu satırı göremiyorsanız yedek tamamlanmamış demektir.

Performans İpuçları

Büyük veritabanlarında yedekleme sürecini hızlandırmak ve sunucuyu daha az yormak için bazı öneriler:

  • --quick parametresini her zaman kullanın. Bu parametre büyük tablolarda veriyi tüm belleğe yüklemek yerine satır satır okur.
  • --compress parametresi sunucu ile istemci arasındaki ağ trafiğini azaltır, uzak sunuculardan yedek alırken kullanışlıdır.
  • Yedekleme işlemlerini off-peak saatlere, yani trafiğin en az olduğu gece saatlerine planlayın.
  • Çok büyük veritabanları için mydumper aracını araştırabilirsiniz. Parallel dump özelliğiyle çok daha hızlı yedek alabilir.
  • nice ve ionice komutlarıyla yedekleme prosesinin önceliğini düşürerek sunucunun ana işlerine daha fazla kaynak ayırmasını sağlayabilirsiniz:
nice -n 19 ionice -c 3 mysqldump -u root --single-transaction buyuk_db | gzip > /backup/buyuk_db.sql.gz

Sonuç

mysqldump belki eski bir araç ama hala işlevselliğini koruyor ve küçük ile orta ölçekli veritabanları için yeterince güvenilir. Önemli olan doğru parametreleri kullanmak, düzenli test etmek ve yedekleme sürecini izlemek.

Burada özetlemek istediğim temel noktalara bakacak olursak: Production InnoDB veritabanlarında her zaman --single-transaction kullanın, root yerine kısıtlı yetkili bir yedekleme kullanıcısı oluşturun, --routines --triggers --events parametrelerini unutmayın, yedekleri sıkıştırın ve birden fazla konuma (farklı disk, uzak sunucu, bulut depolama) yedek alın.

En önemli kural ise şudur: Test etmediğiniz yedek, yedek değildir. Ayda en az bir kez yedeklerinizi test ortamında geri yükleyin ve çalıştığından emin olun. Gün gelir bir şeyler ters gider ve o anda elinizdeki yedeğin gerçekten işe yaradığını önceden bilmek, tüm stresi ortadan kaldırır.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir