Foruma hoş geldin 👋, Ziyaretçi

Forum içeriğine ve tüm hizmetlerimize erişim sağlamak için foruma kayıt olmalı ya da giriş yapmalısınız. Foruma üye olmak tamamen ücretsizdir.

MySQL'de Büyük TEXT/BLOB Verilerinin Performans Etkisi ve Dışarıda Saklama Çözümleri

pixero

Üye
Katılım
14 Mart 2026
Mesajlar
26
Merhaba arkadaşlar, bugün sizlere özellikle forum, blog veya içerik yönetim sistemlerinde sıkça karşılaştığımız bir konudan bahsedeceğim: MySQL tablolarında saklanan büyük boyutlu TEXT (LONGTEXT) veya BLOB verilerinin performansa etkisi ve bu verileri nasıl daha akıllıca yönetebileceğimiz.

Benim sunucularda genelde gördüğüm, bir tablodaki tüm sütunların aynı anda sorgulanması veya yedeklenmesi sırasında bu büyük verilerin işlemi yavaşlattığı yönünde. Örneğin, bir "forum_mesajlari" tablonuz var ve "icerik" sütunu LONGTEXT tipinde. Basit bir "SELECT id, baslik FROM forum_mesajlari" sorgusu bile, eğer veritabanı motoru ayarlarınıza bağlı olarak, bu büyük veri alanlarını sayfalara taşıyorsa performansı etkileyebilir. Ayrıca yedekleme süreleri uzar, bellek kullanımı artar ve replikasyon gecikmeleri yaşanabilir.

🔍 Büyük Verilerin Yol Açtığı Başlıca Sorunlar

Sorgu Performansı: Tablo tarama (full table scan) gerektiren sorgular çok daha yavaş çalışır. Büyük alanlar, disk I/O'yu artırır.
Bellek (RAM) Kullanımı: InnoDB buffer pool, sık erişilen veri sayfalarını tutar. Büyük TEXT/BLOB'lar bu havuzu hızla doldurarak gerçekten önemli olan indeks ve sık kullanılan satır verilerinin havuzdan atılmasına neden olabilir.
Yedekleme ve Taşıma: `mysqldump` ile alınan yedekler devasa boyutlara ulaşır. Sunucu migrasyonu veya veri taşıma işlemleri çok daha uzun sürer.
Replikasyon Gecikmesi: Master sunucudan slave'e aktarılması gereken veri miktarı artar, bu da özellikle yoğun yazma işlemlerinde replikasyon gecikmesine (lag) yol açabilir.

Peki çözüm nedir? Bu büyük verileri ana tablodan ayırmak. İşte benim genelde uyguladığım yöntemler.

⚙️ Çözüm 1: Büyük Veriyi Ayrı Bir Tabloda Saklamak

En temiz ve kontrol edilebilir yöntem budur. Ana tablonuzda sadece bir referans (ID veya dosya yolu) tutarsınız, büyük içerik ise ayrı bir tabloda saklanır.

Örnek bir yapı oluşturalım. Diyelim ki `forum_gonderileri` tablonuz var.

SQL:
-- Ana, performanslı tablomuz (sık sorgulanan veriler burada)
CREATE TABLE forum_gonderileri (
    id INT AUTO_INCREMENT PRIMARY KEY,
    kullanici_id INT,
    baslik VARCHAR(255),
    olusturulma_tarihi DATETIME,
    durum TINYINT,
    icerik_referans_id INT -- Büyük içeriğin ID'si
    -- Diğer sık kullanılan sütunlar...
    INDEX (kullanici_id),
    INDEX (olusturulma_tarihi)
) ENGINE=InnoDB;

-- Büyük veriler için ayrılmış tablomuz
CREATE TABLE gonderi_buyuk_icerik (
    id INT AUTO_INCREMENT PRIMARY KEY,
    gonderi_id INT NOT NULL,
    icerik LONGTEXT,
    FOREIGN KEY (gonderi_id) REFERENCES forum_gonderileri(id) ON DELETE CASCADE
) ENGINE=InnoDB;

Bu durumda, forum listesini çekerken sadece ana tabloyu tararsınız:

SQL:
SELECT id, baslik, kullanici_id FROM forum_gonderileri WHERE durum = 1 ORDER BY olusturulma_tarihi DESC LIMIT 20;

İçeriği göstermek gerektiğinde ise JOIN kullanırsınız:

SQL:
SELECT g., b.icerik FROM forum_gonderileri g LEFT JOIN gonderi_buyuk_icerik b ON g.icerik_referans_id = b.id WHERE g.id = 1234;

💾 Çözüm 2: Dosya Sisteminde Saklama ve Yolunu Tutma

Eğer veriniz gerçekten çok büyük (örneğin base64 kodlanmış resimler, PDF'ler) ve veritabanı yedeklerine dahil olması gerekmiyorsa, dosya sisteminde saklamak mükemmel bir seçenektir. Bu yöntemde veritabanında sadece dosyanın sunucudaki yolu tutulur.

PHP:
// PHP'de basit bir örnek
$dosyaIcerigi = $_FILES['dosya']['tmp_name'];
$hedefDizin = '/var/www/uploads/icerik/';
$benzersizAd = uniqid() . '_' . basename($_FILES['dosya']['name']);
$hedefYol = $hedefDizin . $benzersizAd;

if(move_uploaded_file($dosyaIcerigi, $hedefYol)) {
    // Veritabanına SADECE YOLU kaydet
    $sql = "INSERT INTO forum_gonderileri (baslik, icerik_yolu) VALUES (?, ?)";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$baslik, '/uploads/icerik/' . $benzersizAd]);
}

⚠️ Dikkat Edilmesi Gerekenler ve Optimizasyon İpuçları

InnoDB Barracuda Formatı ve `innodb_file_per_table`: Tablolarınızın `ROW_FORMAT=DYNAMIC` veya `COMPRESSED` (Barracuda formatı) kullandığından emin olun. Bu, büyük verileri ana satır sayfasından ayırıp (off-page) sadece bir işaretçi saklayarak performansı ciddi anlamda artırır. Ayrıca `innodb_file_per_table=ON` ayarı yapın.
TEXT vs. BLOB: Metin için her zaman `TEXT` (VARCHAR, TEXT, LONGTEXT), binary veri (resim, dosya) için `BLOB` kullanın. Karakter seti ve collation işlemleri TEXT için geçerlidir.
SELECT Kullanmayın: Kesinlikle SELECT kullanmaktan kaçının. İhtiyacınız olan sütunları açıkça yazın. Büyük bir alanı yanlışlıkla çekmek performansı mahveder.
Dosya Sistemi Güvenliği: Dosya yolu saklıyorsanız, dosya yükleme dizininin doğrudan web'den erişilememesi için (.htaccess veya nginx kuralları ile) koruma altına alın. Dosya adlarını doğrulayın ve dizin traversal saldırılarına karşı önlem alın.

📊 Ne Zaman Hangi Yöntemi Seçmeliyim?

Ayrı Tablo: İçerikle ilgili arama yapmanız, transaction bütünlüğü korumanız veya verinin yedeklerle birlikte taşınması kritikse.
Dosya Sistemi: Veri boyutu çok büyükse (MB'lar seviyesinde), yedek boyutunu küçültmek istiyorsanız ve dosya erişim yönetimini uygulama katmanında rahatça yapabiliyorsanız.

Sonuç olarak arkadaşlar, MySQL'i bir dosya deposu gibi kullanmamak genel prensibimiz olmalı. Bu basit ayrıştırma işlemi, özellikle trafiği yüksek sistemlerde karşılaşacağınız birçok performans sorununun önüne geçecektir.

Peki siz bu konfigürasyonu kendi sunucularınızda nasıl yapıyorsunuz? Büyük verileri yönetmek için farklı bir yönteminiz var mı? Deneyimlerinizi paylaşın veya aklınıza takılan bir şey olursa aşağıya yazmaktan çekinmeyin.
 

Tema özelleştirme sistemi

Bu menüden forum temasının bazı alanlarını kendinize özel olarak düzenleye bilirsiniz.

Zevkine göre renk kombinasyonunu belirle

Tam ekran yada dar ekran

Temanızın gövde büyüklüğünü sevkiniz, ihtiyacınıza göre dar yada geniş olarak kulana bilirsiniz.

Geri