aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Oyun Sunucusu

MySQL Slow Query Log: Pahalı Sorguları Bulma

Oyun sunucun ya da web uygulaman tökezliyorsa, suçlu çoğu zaman birkaç pahalı SQL sorgusudur ve onları gözle bulmak imkânsızdır. İşte tam bu noktada MySQL slow query log devreye girer: belirlediğin süreden uzun süren her sorguyu sessizce bir dosyaya yazar, böylece tahmin yürütmek yerine veriye bakarsın. Bu yazıda log'u doğru açmayı, doğru ayarları seçmeyi ve en pahalı sorguları sistematik olarak çıkarmayı adım adım anlatıyorum.

Slow query log tam olarak nedir?

Slow query log, çalışması long_query_time saniyesinden uzun süren SQL ifadelerini kaydeden bir MySQL özelliğidir. "Yavaş" tanımı görecelidir: bir Metin2 sunucusunda 0.5 saniye süren bir karakter sorgusu felakettir, bir rapor ekranında 2 saniye normal olabilir. Log her satırda sorgu zamanını, kilit (lock) süresini, taranan satır sayısını ve gönderilen satır sayısını tutar. Asıl güç bu metadatadadır: çoğu zaman sorun sorgunun kendisi değil, sonucu 10 satır olmasına rağmen milyonlarca satır taramasıdır.

Log'u açmak: kalıcı yapılandırma

En sağlam yöntem my.cnf (Debian/Ubuntu'da genelde /etc/mysql/mysql.conf.d/mysqld.cnf) dosyasına yazmaktır. [mysqld] bloğuna şunları ekle:

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

Sonra servisi yeniden başlat: sudo systemctl restart mysql. Ayarlar tek tek şunu yapar:

  • long_query_time — eşik (saniye). Ondalık kabul eder; 0.5 yazabilirsin.
  • log_queries_not_using_indexes — index kullanmayan her sorguyu, hızlı bile olsa loglar. Geliştirmede altın değerinde, ama çok gürültü üretebilir.
  • min_examined_row_limit — bu kadar satırdan az inceleyen sorguları görmezden gelir; küçük tabloların log'u şişirmesini önler.

Yeniden başlatmadan, canlıda açmak

Üretim sunucusunu yeniden başlatamıyorsan, MySQL bu değişkenlerin çoğunu çalışırken (runtime) değiştirmene izin verir. root ile bağlanıp şunları çalıştır:

SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = 'ON';

Dikkat: long_query_time oturum başına okunur, yani sadece yeni bağlantılar bu değeri görür; o anki bağlantı havuzu eski eşiği kullanmaya devam eder. Ayrıca SET GLOBAL ile yapılan değişiklik yeniden başlatmada kaybolur — kalıcılık için yine my.cnf şart.

En pahalı sorguları çıkarmak: pt-query-digest

Ham log dosyasını gözle okumak işkencedir; aynı sorgu yüzlerce kez tekrar eder. Percona Toolkit'in pt-query-digest aracı bu satırları normalleştirir (literal değerleri ? ile değiştirir) ve birbirinin aynısı sorguları tek bir "imza" altında toplar. Kurulum (Debian/Ubuntu):

sudo apt install percona-toolkit
pt-query-digest /var/log/mysql/slow.log > rapor.txt

Rapor en üstte sorguları toplam harcanan süreye göre sıralar — tek seferde 5 saniye süren bir sorgu kadar, 50 ms'lik ama saniyede 200 kez koşan bir sorgu da önemlidir. Her grup için çağrı sayısını, toplam/ortalama süreyi ve örnek bir sorguyu görürsün. Genellikle ilk üç sorgu tüm yükün büyük kısmından sorumludur; ezbere optimizasyon yapmak yerine buraya odaklan.

Bir sorguyu okumak: EXPLAIN ve index

Suçluyu bulduktan sonra başına EXPLAIN ekleyerek MySQL'in planını gör:

EXPLAIN SELECT * FROM player WHERE account_id = 4210 ORDER BY level DESC;

Çıktıda dikkat edilecek alanlar:

  • typeALL görüyorsan tam tablo taraması var, bu kötüdür; hedefin ref veya range.
  • keyNULL ise hiçbir index kullanılmıyor demektir.
  • rows — MySQL'in taramayı planladığı tahmini satır sayısı; sonuç kümenden çok büyükse sorun burada.
  • ExtraUsing filesort veya Using temporary ifadeleri sıralama/gruplama için ek maliyet anlamına gelir.

Yukarıdaki örnekte account_id sütununa bir index eklemek taramayı çökertir: CREATE INDEX idx_player_account ON player (account_id);. Sık birlikte filtrelenen sütunlar için bileşik (composite) index düşün, ama gereksiz index de yazma maliyeti getirir — ölçüp ekle.

Log'u kontrol altında tutmak

Slow query log zamanla büyür; üretimde mutlaka döndür (rotate). Çoğu dağıtımda /etc/logrotate.d/mysql-server hazır gelir, yoksa basit bir kural yeterli. Teşhis bittiğinde log_queries_not_using_indexes'i kapat; bu seçenek küçük ama indexsiz sorgularla dosyayı doldurabilir. Disk I/O'nun çok değerli olduğu yoğun sunucularda log'u sadece sorun araştırırken aç, kalıcı olarak long_query_time'ı makul bir eşikte (örneğin 1) tut.

Sık Sorulan Sorular

Slow query log performansı yavaşlatır mı?

Makul bir eşikle etkisi ihmal edilebilir, çünkü yalnızca eşiği aşan sorgular yazılır. Asıl maliyet log_queries_not_using_indexes açıkken gelir: yüksek trafikli bir sunucuda bu, log dosyasını ve disk yazımını hızla şişirebilir. Teşhis dışında kapalı tut.

long_query_time'ı kaça ayarlamalıyım?

Başlangıç için 1 saniye iyidir. Hiçbir şey yakalanmıyorsa kademeli düşür (0.5, sonra 0.2). Çok düşük değer log'u gürültüyle doldurur; amacın en pahalı sorguları görmek, her sorguyu değil.

Log dosyası yerine tabloya yazabilir miyim?

Evet, log_output = 'TABLE' ile kayıtlar mysql.slow_log tablosuna gider ve SQL ile sorgulanabilir. Ancak dosya çıktısı pt-query-digest ile çok daha pratiktir; çoğu durumda dosya tercih edilir.

Sunucun yavaşlıyor ve nereden başlayacağını bilemiyorsan, slow query log'u açıp ilk pt-query-digest raporunu birlikte yorumlayabiliriz. MySQL performans denetimi ve sorgu optimizasyonu için benimle iletişime geç.

Bu kategorideki tüm yazılar →

Devamı için