Sunucu Yönetimi & Linux

    MySQL ve MariaDB Performans Optimizasyonu

    MySQL ve MariaDB'de bellek, indeks ve my.cnf ayarlarını düzenleyerek veritabanı performansını artırma rehberi.

    11 dk okuma Güncellendi: 10 Temmuz 2026

    Bir web sitesi ya da uygulama yavaşladığında ilk suçlanan çoğu zaman sunucunun "gücü" olur. Oysa deneyimli bir sistem yöneticisinin ilk baktığı yer neredeyse her zaman veritabanıdır. WordPress, WooCommerce, özel PHP uygulamaları ve panellerin büyük kısmı MySQL ya da onun çatalı olan MariaDB üzerinde çalışır ve bu motorların varsayılan ayarları, "her yerde açılsın" mantığıyla oldukça temkinli seçilmiştir. Yani kutudan çıktığı hâliyle veritabanınız, elindeki belleğin ve diskin ancak küçük bir kısmını kullanır. İyi haber şu: birkaç doğru ayarla, aynı donanımda iki üç kat daha hızlı bir veritabanı elde etmek çoğu zaman mümkündür.

    Bu rehberde bir veritabanı sunucusunu adım adım nasıl hızlandıracağınızı göreceğiz. Önce durumu ölçmeyi, ardından en kritik bellek ayarı olan innodb_buffer_pool_size'ı doğru boyutlandırmayı, yavaş sorgu günlüğü ve EXPLAIN ile darboğazları bulmayı, eksik indeksleri kapatmayı ve max_connections, geçici tablolar ile sorgu önbelleği gibi ayarları ele alacağız. Sonunda da kopyalayıp başlangıç noktası olarak kullanabileceğiniz güvenli bir my.cnf örneği vereceğiz. Temel veritabanı ve kullanıcı yönetimini henüz bilmiyorsanız, önce MySQL / MariaDB temelleri rehberine göz atmanızı öneririm; buradaki komutlar o zeminin üzerine kurulacak.

    Optimizasyona Başlamadan Önce Durumu Ölçün#

    Performans ayarında en büyük hata, ölçmeden ayar değiştirmektir. Rastgele değerleri "internette böyle yazıyordu" diye my.cnf'e yazmak, çoğu zaman fayda yerine belleği tüketip sunucuyu çökertir. Bu yüzden her zaman veritabanının size ne söylediğini dinleyerek başlayın.

    En hızlı yol, sunucu bir süredir çalıştıktan sonra SHOW GLOBAL STATUS ve SHOW GLOBAL VARIABLES çıktısına bakmaktır. Örneğin InnoDB tampon havuzunun ne kadar iyi çalıştığını şu iki değerin oranı söyler:

    SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';
    

    Buradan Innodb_buffer_pool_reads (diskten okumak zorunda kalınan sayfa) ve Innodb_buffer_pool_read_requests (toplam okuma isteği) değerlerini alırsınız. İkincisi birincisinden ne kadar büyükse, verileriniz o kadar bellekten servis ediliyor demektir; oran %99'un altına düşüyorsa tampon havuzunuz küçük kalıyor olabilir.

    Elle uğraşmak istemezseniz, olgunlaşmış bir yardımcı araç olan mysqltuner çok işinize yarar. Sunucu en az 24-48 saat gerçek trafikle çalıştıktan sonra çalıştırın ki önerileri anlamlı olsun:

    wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl
    perl mysqltuner.pl
    

    mysqltuner size bellek kullanımını, önbellek isabet oranlarını, indekssiz sorgu oranını ve somut ayar önerilerini renkli biçimde listeler. Ancak önerilerini körü körüne uygulamayın; her satırın ne anlama geldiğini bu rehberdeki bölümlerle eşleştirerek değerlendirin. Ölçüm bir kez değil, her değişiklikten sonra tekrar yapılacak bir alışkanlıktır.

    InnoDB Buffer Pool En Kritik Ayardır#

    Günümüzde MySQL ve MariaDB tablolarının neredeyse tamamı InnoDB depolama motorunu kullanır. InnoDB'nin performansını belirleyen tek en önemli ayar innodb_buffer_pool_size'dır. Bu havuz, tabloların ve indekslerin bellekte tutulduğu alandır. Ne kadar çok veri belleğe sığarsa, MySQL o kadar az diske gider ve sorgular o kadar hızlanır. Kısacası bu ayar, veritabanının "çalışma masası"nın büyüklüğüdür.

    Genel kural şudur: veritabanı sunucusu yalnızca veritabanına ayrılmışsa (dedike bir sunucu ya da yalnızca MySQL çalışan bir VDS sunucu), toplam RAM'in yaklaşık %60-70'ini tampon havuzuna verebilirsiniz. Aynı makinede web sunucusu, PHP-FPM ve başka servisler de çalışıyorsa (tipik bir tek-sunucu kurulumu) daha temkinli davranıp %25-40 civarında tutun ki diğer servisler ve işletim sistemi belleksiz kalmasın.

    Sunucu RAM'iYalnızca veritabanıWeb + veritabanı birlikte
    2 GB1 GB512 MB
    4 GB2.5 GB1 GB
    8 GB5-6 GB2-3 GB
    16 GB10-12 GB4-6 GB

    Ayarı /etc/mysql/my.cnf (ya da dağıtıma göre /etc/my.cnf.d/ altındaki bir dosya) içine [mysqld] bölümüne yazarsınız:

    [mysqld]
    innodb_buffer_pool_size = 2G
    innodb_buffer_pool_instances = 1
    innodb_log_file_size = 512M
    innodb_flush_method = O_DIRECT
    

    Burada innodb_log_file_size yazma performansını doğrudan etkiler; genelde tampon havuzunun dörtte biri kadar iyi bir başlangıçtır. O_DIRECT ise işletim sisteminin çift önbelleklemesini devre dışı bırakarak belleği daha verimli kullanır. Ayrıca önemli bir uyarı: veritabanınız 500 MB ise 8 GB'lık tampon havuzu ayırmanın hiçbir faydası yoktur; havuz verinizden büyük olduğunda fazlası boşa gider. Havuzu verinizin sığabileceği makul bir boyutta tutmak yeterlidir.

    Yavaş Sorgu Günlüğü ile Darboğazı Yakalayın#

    Sunucunuz genel olarak hızlı görünse bile, tek bir kötü sorgu tüm sistemi kilitleyebilir. Bu sorguları bulmanın en temiz yolu yavaş sorgu günlüğüdür (slow query log). Belirlediğiniz süreden uzun süren her sorguyu bir dosyaya kaydeder, böylece "hangi sorgu yavaş" tahmininden kurtulursunuz.

    my.cnf içine şu satırları ekleyin:

    [mysqld]
    slow_query_log = 1
    slow_query_log_file = /var/log/mysql/slow.log
    long_query_time = 1
    log_queries_not_using_indexes = 1
    

    Burada long_query_time = 1, bir saniyeden uzun süren sorguları yakalar; yoğun sistemlerde bu eşiği 0.5'e indirebilirsiniz. log_queries_not_using_indexes ise indeks kullanmayan sorguları da işaretler ki gizli sorunları görün. Değişiklikten sonra servisi yeniden başlatın:

    sudo systemctl restart mariadb
    

    Log dosyası birkaç saat sonra dolmaya başlar. Ham dosyayı elle okumak yorucudur; onun yerine MySQL ile gelen mysqldumpslow aracı sorguları özetleyip en çok zaman yiyenleri sıralar:

    mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
    

    Bu komut, toplam süreye göre sıralanmış ilk 10 problemli sorgu desenini gösterir. Genellikle listenin en üstündeki bir iki sorguyu düzeltmek, sunucu yükünün büyük kısmını ortadan kaldırır. Yani optimizasyonun %80'i, bu listenin başındaki birkaç sorguya odaklanmaktan ibarettir.

    EXPLAIN ile Sorguyu Analiz Edin ve İndeks Ekleyin#

    Yavaş bir sorgu bulduğunuzda, "neden yavaş" sorusunun cevabı hemen her zaman EXPLAIN komutunda saklıdır. EXPLAIN, MySQL'in bir sorguyu nasıl çalıştırmayı planladığını, hangi indeksi kullandığını ve kaç satır taramak zorunda kaldığını gösterir. Sorgunun başına eklemeniz yeterlidir:

    EXPLAIN SELECT * FROM siparisler WHERE musteri_id = 4821;
    

    Çıktıdaki en kritik iki sütun type ve rows'tur. type değeri ALL ise bu bir tam tablo taramasıdır — MySQL cevabı bulmak için tablodaki her satırı okuyor demektir ve tablonuz büyüdükçe bu felakete dönüşür. rows sütunu da taranan tahmini satır sayısını verir; milyonluk bir tabloda tek bir müşteriyi bulmak için 2 milyon satır tarandığını görüyorsanız, orada bir indeks eksikliği vardır.

    Çözüm, filtrelenen sütuna bir indeks eklemektir:

    CREATE INDEX idx_musteri ON siparisler (musteri_id);
    

    İndeks ekledikten sonra aynı EXPLAIN'i tekrar çalıştırın; type değerinin ref ya da const'a döndüğünü ve rows sayısının binlerden birkaç satıra düştüğünü göreceksiniz. İndeksleme konusunda birkaç pratik kural şöyledir:

    • WHERE, JOIN ve ORDER BY içinde sık kullanılan sütunlar indeks adayıdır.
    • Birden çok sütunla filtreliyorsanız, tek tek indeks yerine birleşik (composite) indeks genelde daha etkilidir; sütun sırası önemlidir.
    • İndeks bedava değildir: her INSERT/UPDATE işleminde indeks de güncellenir, bu yüzden kullanılmayan indeksleri de temizleyin.
    • SELECT * yerine yalnızca ihtiyacınız olan sütunları seçmek hem belleği hem de indeks verimini artırır.

    Aynı mantığın WordPress'e uygulanmış hâlini merak ediyorsanız, WordPress veritabanı optimizasyonu rehberi wp_postmeta gibi şişen tablolar için pratik örnekler içerir.

    Bağlantılar, Geçici Tablolar ve Sorgu Önbelleği#

    Bellek ve indeks ayarları yerine oturduktan sonra, sık karşılaşılan üç ayar daha vardır. Bunlar yanlış ayarlandığında sessizce performans kaybına ya da hatalara yol açar.

    max_connections — Aynı anda kaç istemcinin bağlanabileceğini belirler. Çok düşükse yoğun anlarda kullanıcılar "Too many connections" hatası alır; çok yüksekse her bağlantı bellek ayırdığı için sunucuyu şişirir. Doğru değer trafiğinize ve bağlantı başına bellek kullanımınıza bağlıdır. SHOW STATUS LIKE 'Max_used_connections'; ile gerçek tepe kullanımınızı görüp ona göre pay bırakın:

    [mysqld]
    max_connections = 150
    

    Geçici tablolar (tmp_table_size / max_heap_table_size)GROUP BY, ORDER BY ve karmaşık JOIN içeren sorgular ara sonuçları geçici tablolarda tutar. Bu tablo bellekte tutulabilirse hızlıdır; belirlenen boyutu aşarsa MySQL onu diske yazar ve sorgu birden yavaşlar. Diske dönen geçici tablo oranını SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables'; ile izleyebilirsiniz. İki değeri birlikte ve eşit ayarlamak önemlidir:

    [mysqld]
    tmp_table_size = 64M
    max_heap_table_size = 64M
    

    Sorgu önbelleği (query cache) — Eski bir MySQL özelliğidir ve bugün için genellikle kapalı tutulması önerilir. Yazma yoğun sistemlerde önbelleğin sürekli geçersiz kılınması, faydasından çok kilit (mutex) darboğazı yaratır. MySQL 8.0 bu özelliği tamamen kaldırmıştır; MariaDB'de hâlâ vardır ama çoğu senaryoda kapatmak daha iyidir:

    [mysqld]
    query_cache_type = 0
    query_cache_size = 0
    

    Gerçek önbellekleme ihtiyacınız varsa, veritabanı seviyesinde değil, uygulama seviyesinde Redis ya da benzeri bir bellek deposu kullanmak çok daha ölçeklenebilir bir çözümdür.

    Örnek my.cnf Güvenli Başlangıç Değerleri#

    Aşağıda 4 GB RAM'li, üzerinde hem web sunucusu hem veritabanı çalışan tipik bir sunucu için güvenli bir başlangıç yapılandırması var. Bunu bir hedef değil, üzerine ölçüm yaparak inceltilecek bir taban olarak görün. Sunucunuzun RAM'ine göre özellikle tampon havuzunu yukarıdaki tabloya bakarak ölçekleyin.

    [mysqld]
    # --- InnoDB (en kritik bölüm) ---
    innodb_buffer_pool_size        = 1G
    innodb_buffer_pool_instances   = 1
    innodb_log_file_size           = 256M
    innodb_flush_method            = O_DIRECT
    innodb_flush_log_at_trx_commit = 2
    innodb_file_per_table          = 1
    
    # --- Bağlantılar ---
    max_connections                = 120
    max_allowed_packet             = 64M
    thread_cache_size              = 16
    
    # --- Geçici tablolar ---
    tmp_table_size                 = 32M
    max_heap_table_size            = 32M
    
    # --- Sorgu önbelleği (kapalı) ---
    query_cache_type               = 0
    query_cache_size               = 0
    
    # --- Yavaş sorgu günlüğü ---
    slow_query_log                 = 1
    slow_query_log_file            = /var/log/mysql/slow.log
    long_query_time                = 1
    log_queries_not_using_indexes  = 1
    
    # --- Karakter seti ---
    character-set-server           = utf8mb4
    collation-server               = utf8mb4_unicode_ci
    

    Burada innodb_flush_log_at_trx_commit = 2, her işlemde diske senkron yazma yükünü hafifleterek yazma performansını belirgin biçimde artırır; karşılığında ani bir güç kesintisinde son bir saniyelik veriyi kaybetme riski doğar. Finansal işlem gibi tek bir kaydın kaybının kabul edilemez olduğu sistemlerde bunu varsayılan 1'de bırakın. Değişiklikleri kaydettikten sonra yapılandırmayı test edip servisi yeniden başlatın ve ilk birkaç dakika logları izleyin:

    sudo mysqld --help --verbose > /dev/null   # sözdizimi kontrolü
    sudo systemctl restart mariadb
    sudo tail -f /var/log/mysql/error.log
    

    Servis sorunsuz açıldıysa, birkaç gün trafik topladıktan sonra ölçümü tekrarlayın. Yönetim işlerini kendiniz üstlenmek istemiyorsanız, kurulum ve ince ayarı bizim yaptığımız sunucu yönetimi hizmetiyle bu tarafı tamamen devredebilirsiniz.

    Sık Yapılan Hatalar#

    Deneyimin çoğu, aynı hataları tekrar tekrar görmekten gelir. Aşağıdakiler, performans için ayar yaptığını sanıp aslında durumu kötüleştiren en yaygın yanlışlardır:

    • Ölçmeden ayar değiştirmek. Belleği olmadan innodb_buffer_pool_size = 8G yazmak, sunucuyu OOM (bellek yetersizliği) ile çökertir. Her zaman sunucunuzun gerçek RAM'ine göre karar verin.
    • İndeks yerine daha güçlü sunucu almak. Eksik bir indeks yüzünden yavaşlayan sorgu, iki kat güçlü donanımda hâlâ yavaştır; çünkü sorun donanım değil, tasarımdır.
    • Her sütuna indeks eklemek. İndeks yazma işlemlerini yavaşlatır ve disk kaplar; yalnızca gerçekten sorgulanan sütunları indeksleyin.
    • Yedek almadan ayar oynamak. Bir yapılandırma hatası servisi başlatmayabilir. Değişiklik öncesi hem my.cnf'in hem de verinin yedeğini alın; düzenli yedekleme alışkanlığı bu tür anlarda hayat kurtarır.
    • Eski sürümde ısrar etmek. MySQL/MariaDB'nin yeni sürümleri genelde daha hızlı ve daha güvenlidir. Güncel bir sürüm sunan bir web hosting ya da yönetilen sunucu, tek başına ciddi performans farkı yaratabilir.

    Sıkça Sorulan Sorular#

    innodb_buffer_pool_size değerini ne kadar yapmalıyım?#

    Kabaca kural, veritabanı sunucusu yalnızca MySQL/MariaDB çalıştırıyorsa toplam RAM'in %60-70'i, aynı makinede web sunucusu ve PHP gibi başka servisler de varsa %25-40'ıdır. Ancak veritabanınızın toplam boyutu bu değerden küçükse havuzu verinizden büyük yapmanın anlamı yoktur; fazlası boşa gider. En sağlıklı yol, başlangıçta tabloya göre bir değer verip birkaç gün sonra tampon havuzu isabet oranını ve diskten okuma sayısını ölçerek ince ayar yapmaktır.

    Query cache'i açmalı mıyım kapatmalı mıyım?#

    Çoğu modern senaryoda kapatmalısınız. Sorgu önbelleği, veri her değiştiğinde önbelleğini geçersiz kıldığı için yazma yoğun sitelerde faydadan çok kilit darboğazı yaratır; MySQL 8.0 zaten bu özelliği tamamen kaldırmıştır. Gerçekten önbellekleme ihtiyacınız varsa bunu veritabanı yerine uygulama katmanında Redis ya da Memcached ile çözmek çok daha ölçeklenebilirdir. MariaDB kullanıyor ve emin değilseniz, query_cache_type = 0 ile başlayın ve fark olup olmadığını ölçün.

    Yavaş sorgu günlüğünü sürekli açık tutmak zarar verir mi?#

    Makul bir eşik (long_query_time) ile açık tutmanın performans maliyeti ihmal edilebilir düzeydedir ve karşılığında paha biçilmez bir görünürlük sağlar. Yalnızca eşiği çok düşük tutup her sorguyu loglarsanız, log dosyası hızla büyür ve disk yazma yükü artar. Pratik yaklaşım, günlüğü açık bırakıp eşiği 1 saniye civarında tutmak ve dosyayı logrotate ile düzenli döndürmektir. Böylece hem sorunları yakalar hem de diski doldurmazsınız.

    İndeks eklemek sorguları her zaman hızlandırır mı?#

    Hayır. İndeksler okuma sorgularını hızlandırır ama her yazma işleminde de güncellenmeleri gerektiği için INSERT, UPDATE ve DELETE işlemlerini bir miktar yavaşlatır ve disk alanı kaplarlar. Ayrıca çok küçük tablolarda ya da tablonun büyük kısmını döndüren sorgularda indeks kullanmak fayda getirmeyebilir. Doğru yaklaşım, EXPLAIN çıktısına bakıp gerçekten tam tablo taraması yapan sorgular için hedefli indeksler eklemek ve kullanılmayan indeksleri temizlemektir.

    MySQL mi MariaDB mi daha performanslı?#

    İkisi de aynı kökten geldiği için çoğu iş yükünde performans farkı, sürüm ve yapılandırmadan gelen farkın yanında küçük kalır. MariaDB bazı sürümlerinde belirli sorgu tiplerinde ve depolama motorlarında avantaj sağlar, MySQL ise bazı kurumsal özelliklerde öndedir. Pratikte doğru soru "hangisi" değil, "güncel bir sürümü doğru ayarlarla mı çalıştırıyorum" olmalıdır. İyi yapılandırılmış her ikisi de, kötü yapılandırılmış diğerinden kat kat hızlıdır.

    Paylaşımlı hostingte bu ayarları yapabilir miyim?#

    Paylaşımlı barındırmada my.cnf'e ve sunucu servislerine erişiminiz olmaz; bu ayarlar tüm sunucuyu etkilediği için barındırıcı tarafından yönetilir. Ancak yapabileceğiniz çok şey vardır: sorgularınızı ve indekslerinizi optimize etmek, gereksiz veriyi temizlemek, uygulama önbelleği kullanmak. Sunucu seviyesinde kontrol istiyorsanız, kendi my.cnf'inizi düzenleyebileceğiniz bir sanal sunucu (VPS) ya da VDS çözümüne geçmeniz gerekir. Böylece bu rehberdeki tüm ayarları serbestçe uygulayabilirsiniz.

    Kapanış#

    MySQL ve MariaDB performansı, gizemli bir sanat değil, sistematik bir süreçtir: önce ölç, sonra en büyük darboğazı düzelt, sonra tekrar ölç. Bu döngüde en yüksek getiriyi veren adımlar sırasıyla InnoDB tampon havuzunu doğru boyutlandırmak, yavaş sorgu günlüğü ve EXPLAIN ile gerçek problemli sorguları bulmak, eksik indeksleri kapatmak ve bağlantı, geçici tablo ve önbellek ayarlarını iş yükünüze göre inceltmektir. Rastgele değerler kopyalamak yerine sunucunuzun size söylediklerini dinlediğinizde, çoğu zaman aynı donanımda çok daha hızlı bir veritabanına ulaşırsınız.

    Bir başka gerçek de şu: en iyi ayar bile zayıf bir altyapıyı kurtaramaz. NVMe diskli, bol bellekli ve güncel veritabanı sürümü sunan bir zemin, yaptığınız her optimizasyonun karşılığını görmenizi sağlar. Kendi ayarlarınızı özgürce yapmak istiyorsanız yüksek performanslı bir VDS sunucu, yönetim yükünü tamamen bize bırakmak istiyorsanız sunucu yönetimi hizmetimiz iyi bir başlangıçtır. Hangi yolu seçerseniz seçin, ölçerek ilerleyen bir veritabanı, sitenizin yıllarca hızlı ve kararlı kalmasının en sağlam temelidir.

    MySQLPerformansVeritabanı

    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.