WordPress, yazılım ve IT üzerine notlar
Anasayfa » Sunucu & Linux » MySQL ve MariaDB'de yavaş sorguları bulmak: Slow query log ve EXPLAIN

MySQL ve MariaDB'de yavaş sorguları bulmak: Slow query log ve EXPLAIN

İçindekiler
  1. 1. Yavaş sorgu günlüğünü açın
  2. 2. Günlüğü özetleyin
  3. 3. EXPLAIN ile sorguyu okuyun
  4. 4. Doğru indeksi ekleyin
  5. Sık görülen kötü kalıplar
  6. İndeks her şeyin ilacı değil

top komutunu açtığınızda en üstte mysqld ya da mariadbd görüyorsanız ve işlemci kullanımı sürekli yüksekse, veritabanı bir şeylerle boğuşuyor demektir. Çoğu zaman sebep, binlerce kez çalışan ve her seferinde bütün tabloyu tarayan birkaç kötü sorgudur.

Bu sorguları tahmin etmeye çalışmayın. Veritabanı onları sizin için kaydedebilir.

1. Yavaş sorgu günlüğünü açın

Sunucuyu yeniden başlatmadan, çalışırken açabilirsiniz:

SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = 0;
SHOW VARIABLES LIKE 'slow_query_log_file';

long_query_time = 1 ayarı, bir saniyeden uzun süren sorguları kaydeder. Daha ince bir analiz için 0.5 ya da 0.2 gibi değerler de kullanılabilir. Kalıcı olması için aynı ayarları yapılandırma dosyasına da yazın:

# /etc/my.cnf.d/slow.cnf
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mariadb/slow.log
long_query_time = 1

Bir süre, tercihen yoğun saatleri kapsayacak kadar bekleyin.

2. Günlüğü özetleyin

Ham günlük binlerce satır olabilir. mysqldumpslow aracı benzer sorguları gruplar ve en çok zaman harcayanları sıralar:

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

-s t toplam süreye göre sıralar, -t 10 ilk on sorguyu gösterir. Daha ayrıntılı bir analiz için Percona Toolkit'teki pt-query-digest aracı da çok kullanışlıdır.

Çıktıda şöyle bir satır görebilirsiniz:

Count: 18420  Time=2.31s (42550s)  Rows_examined=184000
SELECT * FROM siparisler WHERE musteri_eposta = 'S' ORDER BY tarih DESC LIMIT N

Bu sorgu 18.420 kez çalışmış, ortalama 2,3 saniye sürmüş ve her seferinde 184.000 satır taramış. Toplam maliyeti 11 saati aşıyor. Suçluyu bulduk.

3. EXPLAIN ile sorguyu okuyun

EXPLAIN SELECT * FROM siparisler
WHERE musteri_eposta = 'ali@ornek.com'
ORDER BY tarih DESC LIMIT 10;
+------+-------------+------------+------+---------------+------+---------+------+--------+-----------------------------+
| id   | select_type | table      | type | possible_keys | key  | key_len | ref  | rows   | Extra                       |
+------+-------------+------------+------+---------------+------+---------+------+--------+-----------------------------+
|    1 | SIMPLE      | siparisler | ALL  | NULL          | NULL | NULL    | NULL | 184000 | Using where; Using filesort |
+------+-------------+------------+------+---------------+------+---------+------+--------+-----------------------------+

Bakılacak sütunlar:

  • type: ALL, bütün tablonun tarandığı anlamına gelir; en kötü durum budur. ref, range ya da const görmek istersiniz.
  • key: Kullanılan indeks. NULL ise hiçbir indeks kullanılmıyor.
  • rows: Taranacağı tahmin edilen satır sayısı.
  • Extra: Using filesort ve Using temporary, sıralama ya da gruplama için ek iş yapıldığını gösterir.

4. Doğru indeksi ekleyin

Sorgu musteri_eposta ile filtreliyor ve tarih ile sıralıyor. Her ikisini kapsayan bir birleşik indeks:

ALTER TABLE siparisler ADD INDEX idx_eposta_tarih (musteri_eposta, tarih);

Sütun sırası önemlidir: Önce eşitlikle filtrelenen sütun (musteri_eposta), sonra sıralanan ya da aralıkla filtrelenen sütun (tarih) gelir. Şimdi EXPLAIN tekrar çalıştırıldığında type: ref, key: idx_eposta_tarih ve rows: 12 gibi bir sonuç görürsünüz. Using filesort ifadesi de kaybolur. Sorgu 2,3 saniyeden birkaç milisaniyeye iner.

Büyük tablolarda ALTER TABLE uzun sürebilir. MariaDB ve MySQL'in güncel sürümleri çoğu indeks eklemeyi tabloyu kilitlemeden (online) yapar, yine de yoğun saatlerin dışında çalıştırmak daha güvenlidir.

Sık görülen kötü kalıplar

İndeksli sütuna fonksiyon uygulamak:

-- İndeks kullanılamaz
WHERE DATE(tarih) = '2026-09-13'
-- İndeks kullanılır
WHERE tarih >= '2026-09-13' AND tarih < '2026-09-14'

Başında joker karakter olan LIKE:

WHERE ad LIKE '%ahmet%'   -- tam tarama
WHERE ad LIKE 'ahmet%'    -- indeks kullanılabilir

Metin içinde arama gerekiyorsa FULLTEXT indeks ya da ayrı bir arama motoru düşünün.

Gereksiz SELECT *: Yalnızca ihtiyacınız olan sütunları seçmek, özellikle büyük metin sütunları olan tablolarda ciddi fark yaratır.

Döngü içinde sorgu (N+1): Yüz siparişi listeleyip her biri için ayrı bir müşteri sorgusu çalıştırmak, 101 sorgu demektir. Tek bir JOIN ya da WHERE id IN (...) sorgusu aynı işi görür.

İndeks her şeyin ilacı değil

Her indeks, ekleme ve güncelleme işlemlerini biraz yavaşlatır ve disk alanı tüketir. Her sütuna indeks eklemek yerine, yavaş sorgu günlüğünün gösterdiği gerçek sorgulara göre indeks ekleyin. Kullanılmayan indeksleri bulmak için MySQL'de sys.schema_unused_indexes görünümü işinize yarar.

İşiniz bitince long_query_time değerini makul bir seviyede bırakın ve günlüğü logrotate ile döndürün. Açık kalan yavaş sorgu günlüğü, sonraki sorunlar için de en iyi erken uyarı sisteminizdir.

Tezcan Kabakçı
Hosting teknik destek uzmanı ve WordPress uzmanı. 2024'ten beri bir hosting şirketinde teknik destek bölümünde çalışıyor; WordPress, DNS ve e-posta sorunlarını her gün yakından görüyor. YouTube kanalı.
Bu yazı 13 Eylül 2026 tarihinde Sunucu & Linux kategorisinde yayınlandı.
Yeni yazılar e-postanıza gelsin

Ayda birkaç e-posta; istediğiniz an tek tıkla ayrılabilirsiniz.

Videolu anlatımlar YouTube'da
Sunucu ve WordPress sorunlarını kısa videolarla anlattığım kanala abone olabilirsiniz. ▶ Kanala abone ol

Yorumlar

Henüz yorum yok. İlk yorumu siz yazın.

Yorum yazın

Yorumlar onaylandıktan sonra yayımlanır. Bağlantı içeren yorumlar spam olarak değerlendirilebilir.