Merhaba arkadaşlar, bugün sizlere MySQL performans analizinin en kritik araçlarından biri olan `EXPLAIN` komutunu nasıl kullanacağınızı ve çıktısını nasıl okuyacağınızı anlatacağım. Yavaş çalışan sorgularınızın nedenini bulmak, indekslerinizin doğru kullanılıp kullanılmadığını görmek istiyorsanız bu rehber tam size göre. Ben de sunucularımda bir sorgu yavaşladığında ilk iş olarak `EXPLAIN` ile analize başlarım.
EXPLAIN Nedir ve Nasıl Kullanılır?
`EXPLAIN` komutu, bize bir SELECT sorgusunun MySQL tarafından nasıl çalıştırılacağını (execution plan) adım adım gösterir. Sorgunun hangi tablolara, hangi sırayla ve hangi indeksleri kullanarak erişeceğini, kaç satırın tarandığını (rows) söyler. Kullanımı çok basit:
Ya da daha detaylı bilgi için `EXPLAIN FORMAT=JSON` kullanabilirsiniz. Bu komutu çalıştırdığınızda sorgu çalıştırılmaz, sadece nasıl çalıştırılacağının planı döner.
EXPLAIN Çıktısındaki Anahtar Sütunlar
Çıktıda göreceğiniz sütunları anlamak çok önemli. En kritik olanları şunlar:
id: Sorgudaki her SELECT için benzersiz bir kimlik. Basit sorgularda genelde 1'dir.
select_type: Sorgu türü (SIMPLE, PRIMARY, SUBQUERY gibi).
table: Erişilen tablonun adı.
type: Bu en önemli sütunlardan biridir. Tabloya nasıl erişildiğini söyler. Performansı değerlendirmek için bu sütuna çok dikkat edin. Değerler (en iyiden en kötüye):
`system`, `const`: Mükemmel. Tek bir satır eşleşir.
`eq_ref`, `ref`: Çok iyi. Bir indeks üzerinden eşleşme.
`range`: İyi. Bir indeks aralığı taraması (BETWEEN, IN, >, <).
`index`: Orta. Tüm indeksin taranması (Full Index Scan).
`ALL`: Çok Kötü. Tüm tablonun taranması (Full Table Scan). Büyük tablolarda felaket demektir. Hemen indeks eklemeyi düşünmelisiniz.
possible_keys: MySQL'nin kullanmayı düşündüğü indekslerin listesi.
key: MySQL'nin gerçekten kullanmayı seçtiği indeks.
key_len: Kullanılan indeksin uzunluğu (byte cinsinden). Kısmi indeks kullanımını anlamak için faydalıdır.
rows: MySQL'nin o adımda bulacağını tahmin ettiği satır sayısı. Bu sayı ne kadar küçükse o kadar iyidir.
Extra: Çok değerli ek bilgiler içerir. Örneğin:
`Using where`: WHERE filtresi uygulanıyor.
`Using index`: Sorgu için gerekli tüm veri indeksten alınıyor (Covering Index). Bu çok iyi bir durumdur.
`Using temporary`: Geçici bir tablo oluşturuluyor. Genellikle GROUP BY veya ORDER BY'da kötü performans işaretidir.
`Using filesort`: Sıralama için ekstra bir adım gerekiyor. Büyük veri setlerinde yavaşlatır.
Pratik Analiz Örneği ve İyileştirme
Diyelim ki `siparisler` adında büyük bir tablonuz var ve tarihe göre filtreleme yapıyorsunuz.
Çıktıda `type: ALL` ve `Extra: Using where` görürseniz, bu tam bir tablo taraması demektir. Sebebi, WHERE koşulundaki `DATE()` fonksiyonudur. İndeksler, sütunun ham hali üzerinde çalışır; fonksiyonlar indeks kullanımını engeller.
Çözüm: Fonksiyondan kurtulup indeks-dostu bir sorgu yazmak.
Eğer `olusturulma_tarihi` sütununda bir indeks varsa (`INDEX (olusturulma_tarihi)`), şimdi çıktıda `type: range` ve `key` sütununda o indeksin adını görmelisiniz. `rows` sayısı da dramatik şekilde düşmüş olacak.
Dikkat Edilmesi Gerekenler ve İpuçları
`EXPLAIN` tahmini bir plandır. Gerçek performansı tam olarak ölçmek için sorguyu çalıştırıp süresine bakın veya `EXPLAIN ANALYZE` (MySQL 8.0+) kullanın.
`rows` sütunu bir tahmindir, gerçek sayıyla birebir aynı olmayabilir.
Bileşik indeks (composite index) oluştururken sütun sırası çok önemlidir. Sorgularınızda en sık kullanılan ve en çok ayırt ediciliği olan sütunu başa yazın.
/var/log/mysql/slow-query.log dosyasını aktif edip yavaş sorguları tespit edin, sonra onları `EXPLAIN` ile analiz edin.
JOIN'li sorgularda, `EXPLAIN` çıktısını yukarıdan aşağıya okumak yerine, `id` değerine göre (aynı `id` değerine sahip satırlar aynı anda çalıştırılır) ve iç içe geçmiş şekilde düşünmelisiniz.
Umarım bu rehber, sorgu optimizasyonu yolculuğunuzda size ışık tutar. `EXPLAIN` çıktısını okumayı öğrendikten sonra, performans sorunlarını tespit etmek ve çözmek çok daha kolay hale geliyor. Siz bu analizleri yaparken nelere dikkat ediyorsunuz? Benim gözden kaçırdığım başka püf noktalar var mı? Ya da takıldığınız bir `EXPLAIN` çıktısı varsa aşağıya yazın, birlikte inceleyelim.
`EXPLAIN` komutu, bize bir SELECT sorgusunun MySQL tarafından nasıl çalıştırılacağını (execution plan) adım adım gösterir. Sorgunun hangi tablolara, hangi sırayla ve hangi indeksleri kullanarak erişeceğini, kaç satırın tarandığını (rows) söyler. Kullanımı çok basit:
SQL:
EXPLAIN SELECT FROM kullanicilar WHERE email = 'ornek@bingunluk.com';
Ya da daha detaylı bilgi için `EXPLAIN FORMAT=JSON` kullanabilirsiniz. Bu komutu çalıştırdığınızda sorgu çalıştırılmaz, sadece nasıl çalıştırılacağının planı döner.
Çıktıda göreceğiniz sütunları anlamak çok önemli. En kritik olanları şunlar:
id: Sorgudaki her SELECT için benzersiz bir kimlik. Basit sorgularda genelde 1'dir.
select_type: Sorgu türü (SIMPLE, PRIMARY, SUBQUERY gibi).
table: Erişilen tablonun adı.
type: Bu en önemli sütunlardan biridir. Tabloya nasıl erişildiğini söyler. Performansı değerlendirmek için bu sütuna çok dikkat edin. Değerler (en iyiden en kötüye):
`system`, `const`: Mükemmel. Tek bir satır eşleşir.
`eq_ref`, `ref`: Çok iyi. Bir indeks üzerinden eşleşme.
`range`: İyi. Bir indeks aralığı taraması (BETWEEN, IN, >, <).
`index`: Orta. Tüm indeksin taranması (Full Index Scan).
`ALL`: Çok Kötü. Tüm tablonun taranması (Full Table Scan). Büyük tablolarda felaket demektir. Hemen indeks eklemeyi düşünmelisiniz.
possible_keys: MySQL'nin kullanmayı düşündüğü indekslerin listesi.
key: MySQL'nin gerçekten kullanmayı seçtiği indeks.
key_len: Kullanılan indeksin uzunluğu (byte cinsinden). Kısmi indeks kullanımını anlamak için faydalıdır.
rows: MySQL'nin o adımda bulacağını tahmin ettiği satır sayısı. Bu sayı ne kadar küçükse o kadar iyidir.
Extra: Çok değerli ek bilgiler içerir. Örneğin:
`Using where`: WHERE filtresi uygulanıyor.
`Using index`: Sorgu için gerekli tüm veri indeksten alınıyor (Covering Index). Bu çok iyi bir durumdur.
`Using temporary`: Geçici bir tablo oluşturuluyor. Genellikle GROUP BY veya ORDER BY'da kötü performans işaretidir.
`Using filesort`: Sıralama için ekstra bir adım gerekiyor. Büyük veri setlerinde yavaşlatır.
Diyelim ki `siparisler` adında büyük bir tablonuz var ve tarihe göre filtreleme yapıyorsunuz.
SQL:
EXPLAIN SELECT FROM siparisler WHERE DATE(olusturulma_tarihi) = '2023-11-15';
Çıktıda `type: ALL` ve `Extra: Using where` görürseniz, bu tam bir tablo taraması demektir. Sebebi, WHERE koşulundaki `DATE()` fonksiyonudur. İndeksler, sütunun ham hali üzerinde çalışır; fonksiyonlar indeks kullanımını engeller.
Çözüm: Fonksiyondan kurtulup indeks-dostu bir sorgu yazmak.
SQL:
-- İyileştirilmiş Sorgu
EXPLAIN SELECT FROM siparisler
WHERE olusturulma_tarihi >= '2023-11-15 00:00:00'
AND olusturulma_tarihi < '2023-11-16 00:00:00';
Eğer `olusturulma_tarihi` sütununda bir indeks varsa (`INDEX (olusturulma_tarihi)`), şimdi çıktıda `type: range` ve `key` sütununda o indeksin adını görmelisiniz. `rows` sayısı da dramatik şekilde düşmüş olacak.
`EXPLAIN` tahmini bir plandır. Gerçek performansı tam olarak ölçmek için sorguyu çalıştırıp süresine bakın veya `EXPLAIN ANALYZE` (MySQL 8.0+) kullanın.
`rows` sütunu bir tahmindir, gerçek sayıyla birebir aynı olmayabilir.
Bileşik indeks (composite index) oluştururken sütun sırası çok önemlidir. Sorgularınızda en sık kullanılan ve en çok ayırt ediciliği olan sütunu başa yazın.
/var/log/mysql/slow-query.log dosyasını aktif edip yavaş sorguları tespit edin, sonra onları `EXPLAIN` ile analiz edin.
JOIN'li sorgularda, `EXPLAIN` çıktısını yukarıdan aşağıya okumak yerine, `id` değerine göre (aynı `id` değerine sahip satırlar aynı anda çalıştırılır) ve iç içe geçmiş şekilde düşünmelisiniz.
Umarım bu rehber, sorgu optimizasyonu yolculuğunuzda size ışık tutar. `EXPLAIN` çıktısını okumayı öğrendikten sonra, performans sorunlarını tespit etmek ve çözmek çok daha kolay hale geliyor. Siz bu analizleri yaparken nelere dikkat ediyorsunuz? Benim gözden kaçırdığım başka püf noktalar var mı? Ya da takıldığınız bir `EXPLAIN` çıktısı varsa aşağıya yazın, birlikte inceleyelim.