Veritabanı Yönetimi

    InnoDB ve MyISAM Karşılaştırması

    İki depolama motorunun kilit, transaction ve dayanıklılık farkları ve güvenli geçiş adımları.

    10 dk okuma Güncellendi: 25 Ağustos 2026

    Eski bir projeyi devraldığında karşılaşacağın ilk sürprizlerden biri, tabloların hâlâ MyISAM motoruyla çalışıyor olmasıdır. Site ayakta, sorgular dönüyor, görünürde bir sorun yok — ta ki sunucu beklenmedik şekilde kapanana ve tablolardan biri bozulana kadar. InnoDB ve MyISAM arasındaki fark, "hangisi daha hızlı" sorusundan çok daha derindir: biri verinin bütünlüğünü garanti eder, diğeri etmez.

    Bu yazıda iki motorun kilitleme modeli, transaction desteği, çökme güvenliği, index yapısı ve bellek kullanımı açısından farklarını somut örneklerle karşılaştıracağım. Ardından MyISAM'ın hâlâ savunulabilir olduğu dar alanları, mevcut tabloları InnoDB'ye taşımanın güvenli adımlarını ve geçiş sırasında karşılaşacağın tuzakları anlatacağım. Sonuç baştan bellidir — modern MySQL'de varsayılan InnoDB'dir ve haklı olarak öyledir — ama nedenini bilmek geçiş kararını doğru vermeni sağlar.

    Temel Fark: Kilitleme Modeli#

    İki motor arasındaki en belirleyici fark kilitleme granülaritesidir. MyISAM tablo düzeyinde kilit alır: bir satırı güncellerken tablonun tamamı yazma için kilitlenir ve bekleyen tüm okuma-yazma işlemleri sıraya girer. InnoDB ise satır düzeyinde kilit alır; iki farklı satırı güncelleyen iki oturum birbirini hiç beklemez.

    Bu farkın pratik sonucu, eşzamanlılık arttıkça katlanarak büyür. Saniyede birkaç yazma alan bir tabloda MyISAM sorun çıkarmaz. Saniyede yüzlerce yazma alan bir tabloda ise her yazma tüm tabloyu bloke eder ve okuma sorguları kuyrukta bekler — site yavaşlamaz, resmen durur.

    -- Tablonun hangi motoru kullandığını gör
    SELECT table_name, engine, table_rows,
           ROUND((data_length + index_length)/1024/1024) AS toplam_mb
    FROM information_schema.tables
    WHERE table_schema = DATABASE()
    ORDER BY (data_length + index_length) DESC;
    
    -- Kilit beklemesi yaşanıyor mu (MyISAM göstergesi)
    SHOW GLOBAL STATUS LIKE 'Table_locks_waited';
    SHOW GLOBAL STATUS LIKE 'Table_locks_immediate';
    

    Table_locks_waited değeri Table_locks_immediate değerinin yüzde birinin üzerindeyse tablo kilidi ciddi bir darboğaz yaratıyor demektir. MyISAM tablolarda bu oran, trafik arttıkça hızla bozulur.

    Transaction, Çökme Güvenliği ve Veri Bütünlüğü#

    MyISAM'da transaction diye bir kavram yoktur. START TRANSACTION yazabilirsin, hata almazsın, ama hiçbir şey yapmaz: ROLLBACK komutu değişikliği geri almaz. Yani iki adımlı bir işlemin ilk adımı başarılı olup ikincisi hata verirse, veritabanı yarım kalmış tutarsız bir durumda kalır ve bunu düzeltmek uygulamanın işidir.

    -- MyISAM tabloda bu "transaction" hiçbir koruma sağlamaz
    START TRANSACTION;
    UPDATE hesap_myisam SET bakiye = bakiye - 100 WHERE id = 1;   -- uygulandı
    UPDATE hesap_myisam SET bakiye = bakiye + 100 WHERE id = 999; -- satır yok
    ROLLBACK;   -- ilk güncelleme GERİ ALINMAZ, para kaybolmuştur
    

    InnoDB ise ACID uyumludur ve tüm işlem ya bütünüyle uygulanır ya da hiç uygulanmaz. Ayrıca redo log sayesinde çökme güvenlidir: sunucu elektrik kesintisiyle kapansa bile, açılışta yarım kalmış işlemler otomatik olarak geri alınır ve tutarlı duruma dönülür.

    MyISAM'da böyle bir kurtarma mekanizması yoktur. Beklenmedik kapanmadan sonra tablolar "bozuk" (crashed) olarak işaretlenir ve elle onarılmaları gerekir:

    -- MyISAM tablo bozulduğunda tipik hata:
    -- ERROR 145: Table 'siparis' is marked as crashed and should be repaired
    CHECK TABLE siparis;
    REPAIR TABLE siparis;
    

    Onarım işlemi büyük tablolarda saatler sürebilir ve bazı durumlarda veri kaybıyla sonuçlanır. Bu senaryonun tam çözüm adımlarını MySQL veritabanı onarma yazısında ele aldım. InnoDB tarafında bu tür bir bakım işlemi rutin olarak gerekmez.

    Bir diğer bütünlük aracı yabancı anahtarlardır. MyISAM sözdizimini kabul eder ama sessizce yok sayar; yani FOREIGN KEY tanımı yazarsın, hata almazsın ve hiçbir kısıt uygulanmaz. Bu, tasarımın kâğıt üzerinde doğru görünüp gerçekte hiçbir koruma sağlamadığı sinsi bir durumdur.

    Özellik Karşılaştırma Tablosu#

    İki motorun farklarını tek tabloda toplarsak:

    ÖzellikInnoDBMyISAM
    KilitlemeSatır düzeyiTablo düzeyi
    Transaction (ACID)VarYok
    Çökme kurtarmaOtomatik (redo log)Yok, elle REPAIR
    Yabancı anahtarDesteklerSessizce yok sayar
    Kümelenmiş indexVar (PK'ya göre)Yok, veri ayrı dosyada
    Veri önbelleğiBuffer pool (veri + index)Yalnızca index (key_buffer)
    FULLTEXT indexVar (5.6+)Var
    Uzamsal (spatial) indexVar (5.7+)Var
    COUNT(*) tüm tabloSayar (yavaş)Anlık (satır sayısı saklanır)
    Tablo başına dosya.ibd.MYD + .MYI
    SıkıştırmaSayfa sıkıştırmamyisampack (salt okunur)
    Bölümleme (partitioning)DesteklerSınırlı
    Varsayılan motorMySQL 5.5 ve sonrasıMySQL 5.1 ve öncesi

    Tablodaki en çok yanlış anlaşılan satır COUNT(*) satırıdır. MyISAM tablo satır sayısını meta veride sakladığı için SELECT COUNT(*) FROM tablo anlık döner; InnoDB ise MVCC nedeniyle her transaction farklı bir sayı görebileceğinden gerçekten saymak zorundadır. Bu, MyISAM lehine gösterilen klasik argümandır ama pratikte çok dar bir avantajdır: WHERE içeren hiçbir sayımda geçerli değildir ve modern MySQL sürümlerinde InnoDB paralel tarama ile bu farkı büyük ölçüde kapatır.

    Index ve Bellek Yapısındaki Fark#

    InnoDB'de tablonun kendisi birincil anahtara göre sıralı bir B+Tree'dir; buna kümelenmiş index (clustered index) denir. Satırın tüm verisi bu ağacın yapraklarında durur. İkincil index'lerin yapraklarında ise satırın tamamı değil birincil anahtar değeri saklanır. Bu tasarımın iki sonucu vardır: birincil anahtara göre erişim çok hızlıdır ve birincil anahtarın kısa olması bütün ikincil index'leri küçültür.

    MyISAM'da böyle bir kümelenme yoktur. Veri .MYD dosyasında sırasız durur, index'ler .MYI dosyasında ayrı tutulur ve index yaprakları doğrudan veri dosyasındaki fiziksel konuma işaret eder. Bu, satır ekleme sırasında yeniden düzenleme gerektirmediği için toplu yüklemeyi hızlandırır ama rastgele okumada ek bir dosya erişimi anlamına gelir.

    Bellek tarafındaki fark daha da önemlidir. InnoDB, hem veri hem index sayfalarını innodb_buffer_pool_size ile tanımlanan tek bir havuzda tutar. MyISAM yalnızca index sayfalarını key_buffer_size içinde tamponlar; veri sayfaları için işletim sisteminin dosya önbelleğine güvenir. Yani MyISAM'da veri önbelleklemesi üzerinde doğrudan kontrolün yoktur.

    [mysqld]
    # InnoDB: veri + index tek havuzda
    innodb_buffer_pool_size = 8G
    
    # MyISAM: yalnızca index; hâlâ MyISAM tablon varsa gerekli
    key_buffer_size         = 256M
    

    Karışık bir sistemde iki tamponu birden ayarlamak zorunda kalırsın ve belleği bölmek zorunda kalırsın; bu, tüm tabloları InnoDB'ye taşımanın gizli faydalarından biridir. Buffer pool boyutunu doğru hesaplamayı InnoDB buffer pool ayarı yazısında, iki tamponun birlikte dengelenmesini ise my.cnf optimizasyon rehberi yazısında anlattım.

    MyISAM Hâlâ Ne Zaman Mantıklı#

    Dürüst olalım: neredeyse hiçbir zaman. Ama tamamen kapatmadan önce, savunulabilir kalan birkaç dar durumu sayalım.

    Birincisi, salt okunur referans tabloları. Bir kez yüklenip bir daha yazılmayan, örneğin posta kodu veya ülke listesi gibi tablolarda tablo kilidi hiç devreye girmez ve MyISAM biraz daha küçük yer kaplar. Yine de kazanç ölçülebilir düzeyde değildir ve tutarlılık riski devam eder.

    İkincisi, MySQL'in kendi sistem tabloları. Eski sürümlerde mysql şemasındaki bazı tablolar MyISAM'dı; MySQL 8.0 ile bunlar da InnoDB'ye taşındı ve veri sözlüğü tamamen işlemsel hâle geldi. Yani bugün bu istisna da ortadan kalkmış durumda.

    Üçüncüsü, myisampack ile sıkıştırılmış arşiv tabloları. Değişmeyen geçmiş veriyi çok küçük bir alanda tutmak için hâlâ kullanılabilir, ama sıkıştırılmış tablo salt okunur hâle gelir ve modern alternatifler (InnoDB sayfa sıkıştırması, harici arşiv depolama) çoğu senaryoda daha iyidir.

    Buna karşılık MyISAM kullanmanın somut bedelleri her zaman geçerlidir: transaction yok, çökme sonrası elle onarım, yabancı anahtar yok, tablo kilidi ve buffer pool'dan yararlanamama. Yeni bir tabloyu MyISAM olarak oluşturmak için 2026 yılında geçerli bir sebep düşünmek zor.

    MyISAM Tablolarını InnoDB'ye Taşımak#

    Geçiş tek komutluk bir işlemdir ama büyük tablolarda uzun sürer ve tablo bu sırada kilitlenir. Sırayla ilerlemelisin:

    1. Envanter çıkar. Hangi tablolar MyISAM, ne kadar büyük, önce hangisi taşınmalı.
    2. Yedek al. Geçiş öncesi tam yedek şart; yöntemi mysqldump ile veritabanı yedekleme yazısında.
    3. Disk alanını doğrula. Dönüşüm sırasında tablonun ikinci bir kopyası oluşur.
    4. Küçükten büyüğe taşı. Önce küçük tablolarla süreci test et.
    5. FULLTEXT ve COUNT(*) bağımlılıklarını gözden geçir. Uygulama tam metin araması yapıyorsa index'i yeniden oluşturman gerekir.
    6. Bellek ayarlarını güncelle. key_buffer_size küçült, innodb_buffer_pool_size büyüt.
    -- 1) MyISAM tabloları listele ve dönüşüm komutlarını üret
    SELECT CONCAT('ALTER TABLE `', table_schema, '`.`', table_name,
                  '` ENGINE=InnoDB;') AS komut,
           ROUND((data_length + index_length)/1024/1024) AS mb
    FROM information_schema.tables
    WHERE engine = 'MyISAM'
      AND table_schema NOT IN ('mysql','information_schema','performance_schema','sys')
    ORDER BY (data_length + index_length);
    
    -- 2) Tek tablo dönüşümü
    ALTER TABLE siparis ENGINE=InnoDB;
    
    -- 3) Sonrasında istatistikleri tazele
    ANALYZE TABLE siparis;
    

    Geçiş sırasında dikkat etmen gereken birkaç nokta var. Birincil anahtarı olmayan tablolar InnoDB'de gizli bir anahtar üretir; performans için tabloya açık bir AUTO_INCREMENT birincil anahtar eklemek çok daha iyidir. AUTO_INCREMENT davranışı iki motorda farklıdır: MyISAM bileşik index'in ikinci kolonunda otomatik artan değere izin verir, InnoDB vermez; böyle bir tasarımın varsa şemayı değiştirmen gerekir. Karakter seti de kontrol edilmeli; dönüşüm fırsatını kullanıp utf8mb4 ve uygun bir collation'a geçmek mantıklıdır.

    Son olarak dönüşüm sonrası doğrulama yap: satır sayılarını karşılaştır, uygulamanın kritik sorgularını çalıştır ve birkaç gün Table_locks_waited ile Innodb_row_lock_waits değerlerini izle. Kilit beklemesinin tablo düzeyinden satır düzeyine inmesi, yoğun sistemlerde en çok hissedilen kazanç olur.

    Sıkça Sorulan Sorular#

    InnoDB MyISAM'dan daha mı yavaştır#

    Eski bir efsanedir ve modern sürümlerde geçerli değildir. Tek kullanıcılı, salt okunur bir karşılaştırmada MyISAM bazı basit sorgularda öne geçebilir, ama gerçek eşzamanlılık altında InnoDB satır kilidi sayesinde belirgin biçimde daha hızlıdır. Ayrıca InnoDB veriyi de buffer pool'da tuttuğu için, bellek doğru ayarlandığında disk erişimi çok daha azdır. Karar verirken tek kullanıcılı testlere değil, gerçek trafiğe bakmalısın.

    MyISAM'dan InnoDB'ye geçiş veri kaybına yol açar mı#

    Doğru yapıldığında hayır; ALTER TABLE ... ENGINE=InnoDB veriyi olduğu gibi taşır. Yine de işlem tabloyu yeniden yazdığı için öncesinde mutlaka tam yedek almalısın. Dikkat edilecek noktalar veri değil şema kaynaklıdır: yabancı anahtar tanımları artık gerçekten uygulanacağı için mevcut tutarsız kayıtlar hata verebilir, bileşik anahtarın ikinci kolonundaki AUTO_INCREMENT kullanımı desteklenmez ve tam metin index'lerini yeniden oluşturman gerekebilir.

    Tablomun hangi motoru kullandığını nasıl öğrenirim#

    SHOW TABLE STATUS LIKE 'tablo_adi'; komutunun Engine sütununa ya da information_schema.tables görünümüne bakabilirsin. Tüm veritabanını tek seferde görmek için SELECT table_name, engine FROM information_schema.tables WHERE table_schema = DATABASE(); sorgusu pratiktir. phpMyAdmin kullanıyorsan tablo listesinde motor bilgisi ayrı bir sütun olarak zaten görünür.

    Yeni tablolar hangi motorla oluşturuluyor#

    MySQL 5.5 ve sonrasında varsayılan depolama motoru InnoDB'dir, yani ENGINE belirtmeden oluşturduğun tablolar InnoDB olur. Sunucunun mevcut ayarını SELECT @@default_storage_engine; ile doğrulayabilirsin. Eski bir sunucudan taşınmış yapılandırmalarda bu değer hâlâ MyISAM olarak ayarlanmış olabilir; öyleyse my.cnf içindeki default_storage_engine satırını düzeltmelisin.

    MyISAM tablo bozulduğunda ne yapmalıyım#

    Önce CHECK TABLE tablo_adi; ile hasarı doğrula, ardından REPAIR TABLE tablo_adi; çalıştır. Onarım başarısız olursa REPAIR TABLE ... USE_FRM seçeneği denenebilir ama bu daha risklidir. Her durumda onarımdan önce ham veri dosyalarının bir kopyasını almalısın. Kalıcı çözüm tabloyu InnoDB'ye taşımaktır; InnoDB'nin redo log tabanlı otomatik kurtarması bu tür elle onarım ihtiyacını ortadan kaldırır.

    InnoDB'de COUNT(*) neden yavaş#

    Çünkü InnoDB, MVCC nedeniyle her transaction'ın farklı sayıda satır görebileceği bir modelde çalışır ve tek bir doğru satır sayısını meta veride saklayamaz; bu yüzden gerçekten saymak zorundadır. MyISAM tablo kilidi kullandığı için böyle bir belirsizlik yaşamaz ve sayıyı hazır tutar. Yaklaşık bir değer yeterliyse information_schema.tables.table_rows sütununu kullanabilir, kesin sayım gerekiyorsa dar bir ikincil index üzerinden saymak maliyeti azaltır.

    Bazı tablolar MyISAM bazıları InnoDB kalabilir mi#

    Teknik olarak evet, MySQL karışık motorlu veritabanlarını destekler. Ancak bunun bir bedeli vardır: belleği iki ayrı tampon arasında bölmek zorunda kalırsın, iki motorun tablolarını kapsayan bir transaction ACID garantisi vermez ve yedekleme stratejin karmaşıklaşır. Geçiş dönemi dışında karışık yapıyı sürdürmemeni, tüm tabloları tek motorda toplamayı öneririm.

    Kapanış#

    Karar aslında sade: yeni tabloları her zaman InnoDB olarak oluştur, elindeki MyISAM tablolarını planlı biçimde taşı ve taşıdıktan sonra belleği key_buffer_size yerine buffer pool'a kaydır. Geçişten önce yedek al, küçük tablolarla başla ve yabancı anahtar ile AUTO_INCREMENT davranışındaki farkları önceden gözden geçir. MyISAM'ı sürdürmenin bugün geçerli bir teknik gerekçesi kalmadı; sürdürmenin bedeli ise ilk beklenmedik kapanmada faturalanıyor.

    Motor geçişi sırasında en çok ihtiyaç duyacağın iki şey yeterli disk alanı ve geri dönebileceğin bir yedektir. Veritabanını rahat bir NVMe alanı ve garanti edilen kaynaklarla çalıştırmak istersen VDS ve bulut sunucu paketlerimiz iyi bir zemin sunar; küçük siteler için web hosting paketlerimizde InnoDB zaten varsayılan gelir. Geçişi ve düzenli yedeği bize bırakmak isterseniz yedekleme ve sunucu yönetimi hizmetlerimiz bu işi üstlenir.

    MySQLInnoDBMyISAM

    Uygulamaya geçmeye hazır mısınız?

    NVMe SSD, ücretsiz SSL ve %99.9 uptime garantisiyle Clou.TR hosting ve sunucu çözümleriyle projenizi hayata geçirin.