
MySQL Performans Optimizasyonu: Index, Sorgu ve Cache Rehberi
MySQL yavaşlığının gerçek nedenini bulmak için slow query log, EXPLAIN analizi ve index stratejisi. InnoDB buffer pool, my.cnf ayarları ve Redis cache entegrasyonu — Buyukweb cPanel ve VDS perspektifinden adım adım rehber.
MySQL Performans Optimizasyonu: Index, Sorgu ve Cache — Adım Adım Rehber
Sayfanız birkaç saniyede açılıyor ama MySQL 100ms'de cevap vermesi gerekirken 3 saniyede mi veriyor? Sunucu CPU'su çıldırmış, web panelindeki "veritabanı yükü" çubuğu kırmızıya mı kaçtı? Büyük ihtimalle sorun sunucu donanımında değil — kötü yazılmış bir sorgu ya da eksik bir index yüzünden her istekte on binlerce satır taranıyor. Bu rehberde Buyukweb hosting altyapısı perspektifinden yavaş MySQL sorgusunu nasıl tespit eder, nasıl düzeltisiniz, adım adım anlatıyoruz.
Buyukweb perspektifi: cPanel paylaşımlı hosting paketlerimizde veritabanı motoru olarak MariaDB 10.6 LTS standart kuruludur. Slow query logları cPanel > phpMyAdmin > Status sekmesinden takip edilebilir; ama doğrudan MySQL komut satırı paylaşımlı hosting'de kısıtlıdır. VDS paketlerinde (₺250/ay'dan) root yetkisi tam verilir:
mysqltuner.plçalıştırabilir,my.cnfdüzenleyebilir,performance_schemasorgulayabilirsiniz. VDS unmanaged çalışır — veritabanı tuning müşteri sorumluluğundadır.
Darboğazı Bulmadan Ayar Yapmayın
İnternette "MySQL hızlandırma" başlıklı pek çok içerik doğrudan innodb_buffer_pool_size ayarıyla başlar. Oysa o ayarı yapmadan önce neyin yavaş olduğunu bilmek gerekir. Çünkü sorun buffer pool olmayabilir; tek bir tabloda düzgün index olmadığı için tüm sunucu dizlerinin üstüne çökmüş olabilir.
Tanı sırası şu şekilde olmalı:
- Slow query log ile yavaş sorguları bul
- EXPLAIN ile o sorguların tarama şeklini gör
- Eksik index ekle — genellikle bu tek adım %80 çözümü getirir
- Gerekiyorsa InnoDB buffer pool ve diğer my.cnf parametrelerini ayarla
- Cache katmanı (Redis/Memcached) ihtiyacı varsa son aşamada ekle
Adım 1: Slow Query Log — Kim Suçlu?
VDS'de Aktif Etme
-- Canlı olarak aktif et (restart gerekmez)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1.0; -- 1 saniyeden uzun sorguları yakala
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
SET GLOBAL log_queries_not_using_indexes = 'ON';
my.cnf'de kalıcı hale getirme:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1
Buyukweb VDS notu: AlmaLinux 9 / Ubuntu 22.04 / Debian 12 paketlerimizde MariaDB 10.11 veya MySQL 8.0 kurulabilir. my.cnf yolu değişebilir:
/etc/my.cnf,/etc/mysql/mariadb.conf.d/50-server.cnfveya/etc/mysql/mysql.conf.d/mysqld.cnf.mysql --help | grep my.cnfile doğru yolu bulabilirsiniz.
Log Dosyasını Analiz Etme
# En uzun süren 10 sorgu
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# En çok tekrarlanan 10 sorgu
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
# Daha kapsamlı analiz: pt-query-digest (percona-toolkit)
pt-query-digest /var/log/mysql/slow.log | head -100
Çıktıda Query_time: 4.3 ve Rows_examined: 450000 gibi satırlar görüyorsanız — bu sorgu her çalıştığında 450 bin satıra dokunuyor. Tek bir index ile bu sayı birkaç yüze düşebilir.
cPanel'de phpMyAdmin ile Slow Query Kontrolü
VDS olmadan, paylaşımlı hosting müşterileri için:
cPanel > Veritabanları > phpMyAdmin > [veritabanı] > Durum (Status) sekmesi
→ "Queries: slow queries" satırına bakın
Ayrıca phpMyAdmin > SQL sekmesinde SHOW GLOBAL STATUS LIKE 'Slow%'; komutuyla anlık sayıyı görebilirsiniz.
Adım 2: EXPLAIN ile Sorgu Plan Analizi
Slow query log'da yakaladığınız sorguya bakın — önüne EXPLAIN koyun, çalıştırın:
EXPLAIN SELECT * FROM wp_posts
WHERE post_type = 'product'
AND post_status = 'publish'
ORDER BY post_date DESC
LIMIT 20;
| EXPLAIN Kolonu | Dikkat Edin |
|---|---|
type: ALL |
Tam tablo taraması — tüm satırlara dokunuyor, çok kötü |
type: index |
Index sırasıyla tam tarama — yine yavaş |
type: range |
Index aralığı — kabul edilebilir |
type: ref |
Index eşleşme — iyi |
type: eq_ref / const |
Tek satır eşleşme — en iyi |
key: NULL |
Hiç index kullanılmamış |
rows: 500000 |
Tahmin edilen taranacak satır sayısı — yüksekse sorun var |
Extra: Using filesort |
Sıralama için geçici disk/bellek kullanımı — index ile giderilebilir |
Extra: Using temporary |
Geçici tablo oluşturuluyor — ciddi kaynak tüketimi |
MySQL 8.0 ve MariaDB 10.9+ için daha ayrıntılı:
EXPLAIN ANALYZE SELECT ...; -- MySQL 8.0 / MariaDB 10.9+
EXPLAIN FORMAT=JSON SELECT ...; -- JSON çıktı
EXPLAIN ANALYZE hem planı hem gerçek çalışma süresini verir; plan ile gerçek arasındaki fark büyükse istatistikler eski demektir — ANALYZE TABLE tablo_adi; çalıştırın.
Adım 3: Index Stratejisi — Sorunun %80'ini Çözen Adım
Hangi Sütunlara Index?
WHEREkoşullarında sık kullanılan sütunlarJOINbağlantısında kullanılan foreign key sütunlarORDER BYveGROUP BYsütunları- Yüksek kardinaliteli sütunlar (çok sayıda benzersiz değer: email, ID, tarih)
- Düşük kardinaliteli sütunlar (evet/hayır, durum: 3-4 değer) — genellikle tek başına index değerini taşımaz, bileşik index içinde işe yarar
Temel Index Örnekleri
-- Tek sütun
ALTER TABLE wp_posts ADD INDEX idx_post_type (post_type);
-- Bileşik (composite) — sıra önemli: önce eşitlik, sonra aralık/sıralama
ALTER TABLE wp_posts ADD INDEX idx_type_status_date
(post_type, post_status, post_date);
-- Benzersiz zorunluluğu olan sütun
ALTER TABLE kullanicilar ADD UNIQUE INDEX idx_email (email);
-- Covering index: sorgu tüm veriyi index'ten alır, tabloya dokunmaz
ALTER TABLE siparis_detay ADD INDEX idx_cover
(siparis_id, urun_id, miktar, fiyat);
Covering index ne zaman kullanılır? EXPLAIN çıktısında Extra: Using index görüyorsanız — MySQL tüm veriyi doğrudan index'ten alıyor, tabloya hiç gitmiyor. Bu en verimli yol.
Index Analizi — Kullanılmayanları Temizle
Index de maliyetsiz değil: yazma operasyonlarında (INSERT, UPDATE, DELETE) her index güncellenir. Gereksiz index yazma yavaşlığı yaratır.
-- Mevcut indexleri gör
SHOW INDEX FROM wp_posts;
-- Kullanılmayan indexleri bul (MySQL 8.0 sys şeması)
SELECT object_schema, object_name, index_name
FROM sys.schema_unused_indexes
WHERE object_schema NOT IN ('mysql', 'performance_schema', 'sys');
-- Index istatistiklerini güncelle
ANALYZE TABLE wp_posts;
-- Gereksiz index sil
DROP INDEX idx_eski ON wp_posts;
WooCommerce ve WordPress'te Sık Karşılaşılan Index Eksikleri
-- wp_postmeta üzerinde meta_key + meta_value arama için
ALTER TABLE wp_postmeta ADD INDEX idx_meta_key_value
(meta_key, meta_value(20));
-- wp_posts'ta post_type + post_status + post_date birlikte kullanılıyor
ALTER TABLE wp_posts ADD INDEX idx_type_status_date
(post_type, post_status, post_date);
-- wp_options'ta autoload sorgulama
ALTER TABLE wp_options ADD INDEX idx_autoload (autoload);
Adım 4: InnoDB Buffer Pool ve my.cnf Ayarları
Buffer pool, InnoDB'nin veri ve index sayfalarını RAM'de tuttuğu havuzdur. Diskten okumak yerine RAM'den okumak 100-1000 kat daha hızlıdır. Hit ratio (oran) %99+ olmalı; düşükse buffer pool yetersizdir.
-- Anlık buffer pool hit ratio
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, 2) AS hit_ratio_pct;
-- Hedef: 99.0 ve üzeri
VDS'de Önerilen my.cnf Bloğu
[mysqld]
# RAM'in %50-70'i — 8 GB RAM'li VDS için
innodb_buffer_pool_size = 5G
innodb_buffer_pool_instances = 4 # Her instance 1.25 GB
# Redo log (MariaDB 10.5+ / MySQL 8.0+ değerleri)
innodb_log_file_size = 512M
innodb_flush_log_at_trx_commit = 2 # 0: en hızlı / 1: ACID / 2: denge
# I/O — NVMe SSD için yüksek tut
innodb_io_capacity = 2000
innodb_io_capacity_max = 4000
innodb_flush_method = O_DIRECT
# Bağlantı ve geçici tablo
max_connections = 300
thread_cache_size = 64
tmp_table_size = 256M
max_heap_table_size = 256M
# Eski query cache — MySQL 8.0 ve MariaDB 10.3+ artık deprecated/removed
# Açık bırakmayın: contention yaratır
query_cache_type = 0
query_cache_size = 0
Önemli:
innodb_flush_log_at_trx_commit = 1tam ACID garantisi sağlar ama herCOMMITte diske yazar. E-ticaret veya finansal uygulama için 1 kullanın. Blog/içerik sitesi için 2 makul denge. 0 en hızlı ama sunucu çökmesinde son saniyedeki işlemler kaybolabilir.
mysqltuner.pl — Hazır Analiz Aracı (VDS)
# İndirip çalıştır
wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl
perl mysqltuner.pl --user root --pass SIFRE
mysqltuner.pl çalışan sunucuya bakarak innodb_buffer_pool_size, max_connections, query_cache gibi parametreler için somut öneriler verir. Sunucu en az 24 saat çalışmış olmalı ki anlamlı istatistik toplansın.
Adım 5: performance_schema ile Derinlemesine Tanı
performance_schema MySQL 5.6 / MariaDB 10.0'dan beri varsayılan gelen hafıza içi tanı sistemidir. Overhead çok düşük (%1-3 CPU).
-- En yavaş sorgu özetleri (MySQL 8.0 ve MariaDB 10.5+)
SELECT
DIGEST_TEXT,
COUNT_STAR AS calisma_sayisi,
ROUND(AVG_TIMER_WAIT / 1e9, 2) AS ort_ms,
ROUND(SUM_TIMER_WAIT / 1e9, 2) AS toplam_ms
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;
-- Tablo I/O — hangi tablo en çok kaynak tüketiyor?
SELECT object_schema, object_name,
ROUND(SUM_TIMER_WAIT / 1e12, 2) AS wait_saniye
FROM performance_schema.table_io_waits_summary_by_table
WHERE object_schema NOT IN ('mysql', 'performance_schema', 'sys')
ORDER BY SUM_TIMER_WAIT DESC LIMIT 10;
Adım 6: Sorgu Yazım Hataları — Gözden Kaçan 5 Tuzak
Index doğru olsa da sorgu yanlış yazılırsa index kullanılmaz:
-- 1. Fonksiyon ile wrap edilen sütun → index çalışmaz
-- KÖTÜ:
WHERE YEAR(siparis_tarihi) = 2025
-- İYİ:
WHERE siparis_tarihi >= '2025-01-01' AND siparis_tarihi < '2026-01-01'
-- 2. LIKE sorgusunda baştaki joker → index çalışmaz
-- KÖTÜ:
WHERE urun_adi LIKE '%çanta%'
-- İYİ (sadece önek arama):
WHERE urun_adi LIKE 'çanta%'
-- LIKE '%...%' için MySQL FULLTEXT index veya Elasticsearch kullanın
-- 3. Örtük tip dönüşümü → index atlanır
-- Tablo: user_id INT, sorguda string geliyor
-- KÖTÜ:
WHERE user_id = '42' -- '42' string, MySQL dönüştürür ama index kaçırabilir
-- İYİ:
WHERE user_id = 42
-- 4. OR ile farklı sütunlar → genellikle tam tablo taraması
-- KÖTÜ:
WHERE kategori_id = 5 OR etiket_id = 12
-- İYİ:
SELECT ... WHERE kategori_id = 5
UNION ALL
SELECT ... WHERE etiket_id = 12
-- 5. SELECT * yerine sadece ihtiyaç duyulan sütunlar
-- KÖTÜ (covering index kullanılamaz):
SELECT * FROM wp_posts WHERE post_type = 'product'
-- İYİ:
SELECT ID, post_title, post_date FROM wp_posts WHERE post_type = 'product'
Cache Katmanı: Ne Zaman Redis, Ne Zaman Veritabanı Yeterli?
MySQL'i ne kadar optimize ederseniz edin, her istek için veritabanına gitmek gereksizdir. Statik ya da seyrek değişen verileri cache'de tutmak hem MySQL yükünü hem de sayfa açılma süresini dramatik biçimde düşürür.
Redis — Session Store ve Uygulama Cache için
# Ubuntu / Debian'da Redis kurulumu (VDS)
apt install redis-server -y
systemctl enable --now redis-server
# /etc/redis/redis.conf
maxmemory 512mb
maxmemory-policy allkeys-lru
// PHP'de Redis ile basit cache
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$cacheKey = 'anasayfa_son_urunler';
$ttl = 300; // 5 dakika
$data = $redis->get($cacheKey);
if (!$data) {
// Veritabanından çek
$data = json_encode(veritabanindan_cek());
$redis->setex($cacheKey, $ttl, $data);
}
$sonuclar = json_decode($data, true);
WordPress'te Redis için object cache eklentileri (W3 Total Cache, LiteSpeed Cache Redis entegrasyonu) Buyukweb cPanel'de aktif edilebilir — destek hattından talep edin.
Ne Zaman MySQL Yeterli, Ne Zaman Redis?
| Senaryo | Tercih |
|---|---|
| E-ticaret ürün listesi (5 dk değişmiyor) | Redis cache |
| Sipariş durumu (anlık tutarlılık şart) | Doğrudan MySQL |
| Session depolama | Redis (MySQL'de lock contention yaratır) |
| Sayfa sayacı, beğeni sayısı | Redis incr() → MySQL'e periyodik yaz |
| Blog yazısı (saatler sabit) | Sayfa cache yeterli (LiteSpeed Cache) |
| Kullanıcı giriş/yetki kontrolü | Redis ile TTL'li cache |
Buyukweb perspektifi: VDS paketlerinde Redis'i kendiniz kuruyorsunuz — tam kontrol sizde. cPanel paylaşımlı hosting'de Redis eklentisinin aktif olması gerekir. Sorgulamak için 0850 302 60 70'i arayın. Tercih etmeyin: Session'ı MySQL'de tutmayı — yüksek trafikte lock satırları oluşturur, "veritabanı yanıt vermiyor" hatalarına yol açar.
WordPress ve WooCommerce için Pratik Bakım Sorguları
-- wp_options autoload boyutu
SELECT ROUND(SUM(LENGTH(option_value)) / 1024 / 1024, 2) AS mb
FROM wp_options WHERE autoload = 'yes';
-- Süresi dolmuş transient temizleme
DELETE FROM wp_options
WHERE option_name LIKE '_transient_%'
AND option_value < UNIX_TIMESTAMP();
-- Eski revisionları sil
DELETE FROM wp_posts WHERE post_type = 'revision';
-- Tablo optimize et (düşük trafikte çalıştırın)
OPTIMIZE TABLE wp_options, wp_posts, wp_postmeta;
Sıkça Sorulan Sorular
Buyukweb cPanel'de slow query log açabilir miyim?
Paylaşımlı hosting'de MySQL/MariaDB global değişkenlerini değiştirme yetkisi yoktur. Ancak phpMyAdmin > Durum (Status) sekmesinden Slow_queries sayacını görebilirsiniz. Hangi sorgunun yavaş olduğunu daraltmak için uygulamanızda sorgu sürelerini loglamanız (Laravel Telescope, WordPress Query Monitor eklentisi) en pratik yol.
Bileşik index'te sütun sırası neden önemli?
MySQL sol-önek kuralına göre çalışır: (a, b, c) index'ini WHERE a=1, WHERE a=1 AND b=2 veya WHERE a=1 AND b=2 AND c=3 sorgularında kullanır. Ama WHERE b=2 sorgusunda bu index kullanılmaz. Sıralamanın en başına kardinalitesi yüksek ve WHERE'de sık geçen sütunu koyun.
InnoDB buffer pool'u ne kadar ayarlamalıyım?
Genel kural: toplam RAM'in %50-70'i. 8 GB RAM'li VDS için 4-5 GB. Ama önce performance_schema veya mysqltuner.pl çıktısına bakın — "InnoDB buffer pool hit ratio" %99'un altındaysa artırın, üstündeyse mevcut değer yeterlidir. Fazla vermek OS ve uygulama için yetersiz bellek bırakır.
MySQL 8.0'daki query cache'i açmalı mıyım?
Hayır. MySQL 8.0'da query cache tamamen kaldırıldı. MariaDB 10.3+ için de query_cache_type = 0 ile kapatın — müdahale gerektiren kilit mekanizması yazma yoğun iş yüklerinde performans düşürür. Uygulama seviyesinde Redis ile cache yapın.
EXPLAIN'de "Using filesort" görüyorum, kötü mü?
Her zaman değil — küçük result set için MySQL bellekte sort yapar, hızlıdır. Sorun EXPLAIN çıktısında rows sayısı yüksekken "Using filesort" varsa: o sıralama için yüz binlerce satır işleniyor demektir. Çözüm: ORDER BY sütunlarını bileşik index'e ekleyin.
pt-query-digest ile mysqldumpslow arasındaki fark ne?
mysqldumpslow MariaDB/MySQL'in içinde gelen temel araç — hızlı ve basit. pt-query-digest ise percona-toolkit'in parçası: query fingerprintleme, zaman dilimlerine göre filtreleme, yüzdelik istatistikler üretir. Büyük ve aktif sistemlerde pt-query-digest çok daha ayrıntılı rapor verir. VDS'de kurulum:
# AlmaLinux / RHEL 9
yum install percona-toolkit -y
# Ubuntu / Debian
apt install percona-toolkit -y
pt-query-digest /var/log/mysql/slow.log --since 3h | head -200
Session'ları Redis'e taşımanın MySQL'e faydası var mı?
Evet — özellikle yüksek eş zamanlı kullanıcı (100+) olan sitelerde büyük fark eder. Her sayfa yüklemede PHP oturumu MySQL'de güncelliyorsa bu UPDATE satırları row-level lock üretir. Redis'e taşındığında MySQL yalnızca gerçek iş mantığı sorgularına odaklanır; ortalama sorgu süresi ve bağlantı sayısı düşer.
Sonuç
MySQL veya MariaDB performans optimizasyonu "en büyük sunucu al, sorun çözülür" mantığıyla olmaz. Çözüm sırası: slow query log → EXPLAIN → index → my.cnf → cache. Adımları atlarsanız yanlış sorunu çözürsünüz. Buyukweb cPanel hosting'de phpMyAdmin ve Query Monitor ile temel tanı yapılabilir; daha ileri seviye tuning için root yetkili VDS gereklidir. Redis cache katmanı ile MySQL'in sırtındaki yükü önemli ölçüde azaltmak mümkün — ama önce hangi sorgular yavaş, onu bulun.
Teknik destek için: 0850 302 60 70.
İlgili Büyükweb Hizmetleri
Veritabanı yoğun uygulamalar için altyapı seçeneklerimiz:
- cPanel Web Hosting — MariaDB 10.6 LTS, phpMyAdmin dahil
- VDS Sunucu — root yetkili, MySQL 8.0 veya MariaDB 10.11 serbestçe kurulabilir
- E5 v4 VDS — NVMe SSD, yüksek IOPS, veritabanı odaklı iş yükleri için
- WordPress Hosting — LiteSpeed + MariaDB optimize
Sorularınız için 0850 302 60 70 numaralı destek hattımıza veya iletişim sayfamıza yazabilirsiniz.
Veritabanı Yönetimi İlgili Hizmetlerimiz
Bu yazıda anlatılan teknik konuyu profesyonel altyapıyla deneyimleyin
Etiketler:

