MySQL veya MariaDB kurduğunuzda, pek çok DBA ve sistem yöneticisi storage engine seçimine yeterince dikkat etmez. “Varsayılan ne ise onu kullanayım” mantığıyla devam edilir ve bu durum ilerleyen süreçte ciddi performans sorunlarına, veri kayıplarına veya gereksiz kaynak tüketimine yol açar. Oysa doğru storage engine seçimi, veritabanınızın hem güvenilirliğini hem de hızını doğrudan etkiler.
Storage Engine Nedir?
MySQL mimarisinde storage engine, verinin fiziksel olarak nasıl depolandığını, okunduğunu ve yazıldığını belirleyen alt katmandır. SQL katmanı sorguları alır ve parse eder, storage engine ise bu sorguların disk üzerinde nasıl gerçekleştirileceğini yönetir. Bu ayrım MySQL’i diğer veritabanlarından ayıran önemli bir özelliktir; aynı veritabanı sunucusunda farklı tablolar için farklı storage engine kullanabilirsiniz.
MySQL’de onlarca storage engine bulunsa da pratikte neredeyse herkesin karşılaştığı iki engine vardır: InnoDB ve MyISAM. Her ikisinin de güçlü yanları, zayıf yanları ve ideal kullanım senaryoları birbirinden önemli ölçüde farklıdır.
MyISAM: Eski Düzenin Ustası
MyISAM, MySQL’in ilk yıllarından beri var olan, uzun süre varsayılan storage engine olarak kullanılan bir yapıdır. MySQL 5.5 sürümüne kadar varsayılan olarak geliyordu. Basit yapısı sayesinde bazı okuma ağırlıklı senaryolarda hala rekabetçi performans gösterir.
MyISAM’ın Teknik Özellikleri
MyISAM her tablo için üç dosya oluşturur:
- .frm: Tablo tanımı (schema bilgisi)
- .MYD: Gerçek veri dosyası (MYData)
- .MYI: İndeks dosyası (MYIndex)
Bu yapının en önemli özelliği, transaction desteğinin olmamasıdır. MyISAM’da BEGIN/COMMIT/ROLLBACK çalışmaz. Bir yazma işlemi başladığında ya tamamlanır ya da yarıda kalır; geri alma mekanizması yoktur.
Locking mekanizması açısından MyISAM tablo düzeyinde kilit (table-level locking) kullanır. Bir sorgu tabloya yazarken tüm tablo kilitlenir ve diğer tüm okuma/yazma işlemleri beklemek zorunda kalır.
# MyISAM tablo oluşturma örneği
mysql -u root -p -e "
CREATE TABLE log_archive (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
log_date DATE NOT NULL,
hostname VARCHAR(100),
log_message TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_log_date (log_date),
INDEX idx_hostname (hostname)
) ENGINE=MyISAM;
"
MyISAM’ın Güçlü Yanları
- Full-text search: Eskiden yalnızca MyISAM destekliyordu, ancak MySQL 5.6+ ile InnoDB da bu özelliği kazandı
- COUNT() sorguları: MyISAM tablonun toplam satır sayısını meta bilgide tutar, COUNT() anında döner
- Küçük footprint: InnoDB’ye kıyasla daha az bellek ve disk alanı kullanır
- Sıkıştırma: myisampack aracıyla salt okunur tablolar sıkıştırılabilir
MyISAM’ın Ciddi Zayıflıkları
- Transaction desteği yok, ACID uyumluluk yok
- Tablo düzeyinde kilit, eş zamanlı yazma işlemlerinde darboğaz yaratır
- Çökme sonrası veri bütünlüğü garanti edilmez
- Foreign key constraint desteği yok
- Row-level locking mümkün değil
InnoDB: Modern Standart
MySQL 5.5 ile birlikte varsayılan storage engine olan InnoDB, kurumsal düzeyde veri bütünlüğü ve eş zamanlılık sunar. MariaDB da dahil olmak üzere tüm modern MySQL uyumlu sistemlerde InnoDB birincil tercih olmuştur.
InnoDB’nin Teknik Özellikleri
InnoDB, ACID uyumlu bir storage engine’dir:
- Atomicity: İşlem ya tamamen gerçekleşir ya da hiç gerçekleşmez
- Consistency: Veri her zaman tutarlı bir durumda kalır
- Isolation: Eş zamanlı işlemler birbirini olumsuz etkilemez
- Durability: Tamamlanan işlemler sistem çökmesinden etkilenmez
InnoDB, row-level locking kullanır. Yani bir satıra yazılırken yalnızca o satır kilitlenir, diğer satırlar okunabilir ve güncellenebilir durumda kalır. Bu özellik yüksek eş zamanlılık gerektiren uygulamalarda devrim niteliğindedir.
# Mevcut veritabanındaki tüm tabloların engine bilgisini kontrol et
mysql -u root -p -e "
SELECT
TABLE_NAME,
ENGINE,
TABLE_ROWS,
ROUND(DATA_LENGTH/1024/1024, 2) AS 'Data (MB)',
ROUND(INDEX_LENGTH/1024/1024, 2) AS 'Index (MB)'
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'your_database_name'
ORDER BY DATA_LENGTH DESC;
"
InnoDB’nin Buffer Pool Yapısı
InnoDB’nin performansının sırrı buffer pool‘dur. Sık erişilen veriler ve indeksler bellekte tutulur, böylece disk I/O minimize edilir. Bir production sunucusunda buffer pool boyutunu doğru ayarlamak kritik öneme sahiptir.
# MySQL yapılandırma dosyasını düzenle
# /etc/mysql/mysql.conf.d/mysqld.cnf veya /etc/my.cnf
# Sunucunuzda 16GB RAM varsa buffer pool için 10-12GB ayırabilirsiniz
grep -E "innodb_buffer_pool" /etc/mysql/mysql.conf.d/mysqld.cnf
# Mevcut buffer pool kullanımını kontrol et
mysql -u root -p -e "
SHOW STATUS LIKE 'Innodb_buffer_pool%';
"
# /etc/mysql/mysql.conf.d/mysqld.cnf içine eklenecek InnoDB ayarları
cat >> /etc/mysql/mysql.conf.d/mysqld.cnf << 'EOF'
[mysqld]
# Buffer pool - toplam RAM'in %70-80'i
innodb_buffer_pool_size = 12G
# Buffer pool instances - her biri için 1-2GB ideal
innodb_buffer_pool_instances = 8
# Log dosyası boyutu - buffer pool'un %25'i
innodb_log_file_size = 3G
# Flush method - SSD için önerilir
innodb_flush_method = O_DIRECT
# Her transaction sonrası fsync - veri güvenliği için 1 bırakın
innodb_flush_log_at_trx_commit = 1
EOF
Gerçek Dünya Senaryosu 1: E-Ticaret Platformu
Bir e-ticaret sitesi düşünün. Sipariş tablosu, kullanıcı tablosu, ödeme tablosu, stok tablosu… Bunların hepsinde tutarlılık kritiktir.
Bir kullanıcı sipariş verdiğinde şunlar olmalıdır:
- Sipariş kaydı oluşturulmalı
- Stok miktarı düşürülmeli
- Ödeme kaydı oluşturulmalı
Bu üç adımın tamamının atomik olması gerekir. Herhangi birinde hata olursa diğerlerinin de geri alınması şarttır. MyISAM ile bu mümkün değildir.
-- InnoDB ile transaction kullanımı - e-ticaret örneği
START TRANSACTION;
-- Sipariş oluştur
INSERT INTO orders (user_id, total_amount, status, created_at)
VALUES (1042, 299.99, 'pending', NOW());
SET @order_id = LAST_INSERT_ID();
-- Stok düş
UPDATE products
SET stock_quantity = stock_quantity - 1
WHERE product_id = 558 AND stock_quantity > 0;
-- Etkilenen satır yoksa (stok bitti) rollback yap
-- Uygulama katmanında kontrol edilir
-- Ödeme kaydı oluştur
INSERT INTO payments (order_id, amount, payment_method, status)
VALUES (@order_id, 299.99, 'credit_card', 'completed');
-- Her şey başarılıysa commit
COMMIT;
-- Hata durumunda:
-- ROLLBACK;
Bu senaryo MyISAM ile çalışsaydı, network kesintisi veya uygulama hatası durumunda stok düşmüş ama sipariş kaydı oluşturulmamış olabilirdi. InnoDB bu tür tutarsızlıkları engeller.
Gerçek Dünya Senaryosu 2: Log Arşiv Sistemi
Öte yandan sadece log verilerini arşivleyen, hiç güncellenmeyecek, yalnızca okunacak bir tablo düşünün. Ayda bir kez büyük miktarda veri eklenir, sonra yalnızca analiz için okunur. Bu tabloda:
- Transaction gerekmez
- Eş zamanlı yazma olmaz
- Hız ve düşük kaynak tüketimi önceliklidir
Bu durumda MyISAM hala geçerli bir seçenek olabilir. Özellikle myisampack ile sıkıştırılmış tablo boyutu dramatik biçimde küçülür.
# MyISAM tablosunu sıkıştır (salt okunur arşiv tablolar için)
# Önce tabloyu kapat
mysql -u root -p -e "FLUSH TABLES log_archive;"
# Tabloyu sıkıştır
myisampack /var/lib/mysql/your_database/log_archive.MYI
# İndeksleri yeniden oluştur
myisamchk -rq /var/lib/mysql/your_database/log_archive.MYI
# Sıkıştırılmış tabloyu kontrol et
myisamchk -dvv /var/lib/mysql/your_database/log_archive.MYI
MyISAM’dan InnoDB’ye Geçiş
Eğer eski bir sistemde MyISAM tablolar varsa ve InnoDB’ye geçirmek istiyorsanız, bu işlem dikkatli planlanmalıdır. Özellikle production sistemlerde.
# Tek bir tabloyu InnoDB'ye dönüştür
mysql -u root -p your_database -e "ALTER TABLE orders ENGINE=InnoDB;"
# Tüm MyISAM tabloları bulup InnoDB'ye dönüştüren script
mysql -u root -p -e "
SELECT CONCAT('ALTER TABLE ', TABLE_SCHEMA, '.', TABLE_NAME, ' ENGINE=InnoDB;')
FROM information_schema.TABLES
WHERE ENGINE = 'MyISAM'
AND TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema')
ORDER BY TABLE_SCHEMA, TABLE_NAME;
" | grep "ALTER TABLE" > convert_to_innodb.sql
# Oluşturulan script'i incele
cat convert_to_innodb.sql
# Onaylandıktan sonra çalıştır
# mysql -u root -p < convert_to_innodb.sql
Dikkat: Büyük tablolarda ALTER TABLE işlemi tabloyu kilitler ve uzun sürer. Production’da pt-online-schema-change veya gh-ost gibi araçlar kullanın.
InnoDB ile Deadlock Yönetimi
InnoDB’nin row-level locking özelliği büyük avantaj sağlasa da yanlış uygulama tasarımında deadlock sorunlarına yol açabilir. İki işlem birbirinin beklediği kaynağı tuttuğunda deadlock oluşur. InnoDB bu durumu otomatik tespit eder ve bir işlemi rollback yapar.
# Deadlock bilgilerini görüntüle
mysql -u root -p -e "SHOW ENGINE INNODB STATUSG" | grep -A 40 "LATEST DETECTED DEADLOCK"
# InnoDB durumunu log dosyasına yaz
mysql -u root -p -e "
SET GLOBAL innodb_print_all_deadlocks = 1;
"
# Aktif kilitleri ve bekleyen işlemleri gör
mysql -u root -p -e "
SELECT
r.trx_id AS waiting_trx_id,
r.trx_mysql_thread_id AS waiting_thread,
r.trx_query AS waiting_query,
b.trx_id AS blocking_trx_id,
b.trx_mysql_thread_id AS blocking_thread,
b.trx_query AS blocking_query
FROM information_schema.innodb_lock_waits w
INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;
"
Deadlock’ları minimize etmek için uygulamanızda işlemleri her zaman aynı sırayla gerçekleştirin ve transaction’ları mümkün olduğunca kısa tutun.
Performans Karşılaştırması: Hangi Durumda Ne Kullanılır
Teorik karşılaştırma yerine pratik karar kriterleri üzerinden gitmek daha sağlıklı olur.
InnoDB kullanmanız gereken durumlar:
- Uygulamanız INSERT/UPDATE/DELETE işlemleri yapıyorsa
- Veri tutarlılığı kritikse (finans, e-ticaret, kullanıcı verileri)
- Eş zamanlı çok sayıda kullanıcı varsa
- Foreign key ilişkileri kullanılıyorsa
- Çökme sonrası otomatik recovery gerekiyorsa
- MVCC (Multi-Version Concurrency Control) ihtiyacınız varsa
MyISAM’ı hala değerlendirebileceğiniz durumlar:
- Tamamen salt okunur, arşiv niteliğinde tablolar
- Log analiz tabloları (yazma tek seferlik ve batch)
- MySQL 5.5 öncesi sistemlerde full-text search
- Çok küçük, düşük trafik bloglar veya static site veritabanları
- Bellek kısıtlı sistemlerde çok sayıda küçük tablo
my.cnf Üzerinden Varsayılan Engine Ayarı
Tüm yeni tabloların InnoDB ile oluşturulmasını sağlamak için my.cnf’de varsayılan engine’i belirtebilirsiniz:
# Mevcut varsayılan engine'i kontrol et
mysql -u root -p -e "SELECT @@default_storage_engine;"
# my.cnf veya mysqld.cnf içine ekle
echo "default_storage_engine = InnoDB" >> /etc/mysql/mysql.conf.d/mysqld.cnf
# MySQL servisini yeniden başlat
systemctl restart mysql
# Değişikliği doğrula
mysql -u root -p -e "SELECT @@default_storage_engine;"
# MariaDB için de aynı şekilde
systemctl restart mariadb
InnoDB Monitoring ve Tuning
Production ortamında InnoDB’nin sağlığını düzenli olarak izlemek gerekir:
# InnoDB buffer pool hit rate hesapla - %99 üstü olmalı
mysql -u root -p -e "
SELECT
ROUND(
(1 - (
(SELECT variable_value FROM performance_schema.global_status WHERE variable_name = 'Innodb_buffer_pool_reads') /
(SELECT variable_value FROM performance_schema.global_status WHERE variable_name = 'Innodb_buffer_pool_read_requests')
)) * 100,
4) AS buffer_pool_hit_rate;
"
# InnoDB genel istatistikleri
mysql -u root -p -e "
SHOW STATUS LIKE 'Innodb_%';
" | grep -E "(rows_read|rows_inserted|rows_updated|rows_deleted|buffer_pool_hit_rate)"
Buffer pool hit rate %99’un altındaysa buffer pool boyutunuzu artırmanız gerekebilir. Bu metrik, veritabanı performansının en kritik göstergelerinden biridir.
MariaDB’de Durum
MariaDB, InnoDB yerine kendi geliştirdiği Aria storage engine’i ve XtraDB (InnoDB’nin optimize edilmiş fork’u) ile gelir. Ancak modern MariaDB sürümlerinde InnoDB ile tam uyumluluk sağlanmıştır. MariaDB kullanıyorsanız öneriler temelde aynıdır; InnoDB (veya XtraDB) production workload için standart tercih olmalıdır.
# MariaDB'de storage engine listesini gör
mysql -u root -p -e "SHOW ENGINESG"
# MariaDB'de varsayılan engine kontrolü
mysql -u root -p -e "SELECT @@storage_engine;"
Sonuç
InnoDB ve MyISAM arasındaki seçim, 2024 itibarıyla büyük ölçüde netleşmiştir. Yeni projelerde InnoDB kullanın, bu konuda ikinci kez düşünmenize gerek yok. Transaction desteği, row-level locking, foreign key kısıtlamaları ve otomatik crash recovery, modern web uygulamalarının temel gereksinimleri haline gelmiştir. MyISAM’ın sunduğu minimal avantajlar bu kriterlerin çok gerisinde kalır.
MyISAM’ın hala geçerli olduğu tek gerçek senaryo, tamamen statik ve arşiv niteliğindeki tablolardır; o da genellikle sıkıştırma ihtiyacı olan, büyük boyutlu, sadece okunacak veri setleridir.
Eski bir sistemde MyISAM tablolar buluyorsanız, bunları InnoDB’ye migrate etmek için acele etmenize gerek yok, ancak bir plan yapın ve uygun bakım pencerelerinde geçişi gerçekleştirin. Özellikle finansal veriler, kullanıcı oturumları ve işlem kayıtları barındıran tablolar için bu geçiş öncelikli olmalıdır.
Son olarak, hangi engine’i seçerseniz seçin, düzenli yedekleme ve monitoring ihmal edilmemelidir. InnoDB’nin sağladığı crash recovery, bir yedekleme stratejisinin yerini tutmaz; sadece tamamlayıcıdır. Veritabanı yönetimi, doğru araçları seçmekten çok daha fazlasını gerektirir.