MySQL Slow Query Log Analizi ve İndeks Optimizasyonu: Performans Darboğazlarını Giderme
MySQL veritabanı performansının sürekli izlenmesi, kritik iş yüklerinde istikrarlı bir operasyonel deneyim sunmak için temeldir. Uygulamaların yanıt sürelerinin uzaması veya veritabanı sunucusunun kaynak tüketiminin anormal artışı genellikle yavaş çalışan SQL sorgularından kaynaklanır. Bu tür sorunları tespit etmenin ve gidermenin en etkili yollarından biri, MySQL Slow Query Log mekanizmasını kullanmak ve ardından indeks optimizasyonları yapmaktır.
MySQL Slow Query Log Nedir ve Nasıl Çalışır?
MySQL Slow Query Log, belirli bir süre eşiğini (long_query_time) aşan tüm sorguları kaydetmek için tasarlanmış bir özelliktir. Bu log dosyası, veritabanı yöneticilerine ve geliştiricilere performans sorunlarına yol açan sorguları belirleme konusunda paha biçilmez bir içgörü sağlar. Varsayılan olarak genellikle kapalıdır veya yüksek bir long_query_time değeri ile gelir.
Sorgu yavaşlığını tespit etmek için kritik iki parametre bulunur:
slow_query_log: Bu parametre, yavaş sorgu logunun etkin olup olmadığını belirler. Değeri ON veya OFF olabilir.long_query_time: Bir sorgunun 'yavaş' kabul edilmesi için gereken saniye cinsinden süreyi belirler. Örneğin, 1 saniye olarak ayarlanırsa, yürütülmesi 1 saniyeden uzun süren tüm sorgular loglanır.
my.cnf dosyasında bu parametreleri şu şekilde ayarlayabiliriz:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 1
log_queries_not_using_indexes = 1Yukarıdaki yapılandırma, yavaş sorgu logunu etkinleştirir, log dosyasının konumunu belirtir, 1 saniyeden uzun süren sorguları kaydeder ve indeks kullanmayan tüm sorguları da loglar (log_queries_not_using_indexes = 1). Bu son ayar, indeks eksikliği nedeniyle yavaş çalışan sorguları tespit etmek için özellikle faydalıdır.
Her bir log kaydı, sorgunun yürütülme zamanı (Query_time), kilitlenme zamanı (Lock_time), gönderilen satır sayısı (Rows_sent) ve incelenen satır sayısı (Rows_examined) gibi detayları içerir. Bu metrikler, sorgunun I/O veya CPU yoğunluğunu, tablo kilitlenmelerinden ne kadar etkilendiğini ve tarama verimliliğini gösterir.
Slow Query Log Analiz Araçları
Ham slow query log dosyalarını manuel olarak incelemek, özellikle yoğun bir veritabanı ortamında, pratik değildir. Bu noktada özelleşmiş analiz araçları devreye girer. En yaygın kullanılan ve etkili araçlardan ikisi mysqldumpslow (MySQL'in kendi paketi içinde gelir) ve Percona Toolkit'in pt-query-digest aracıdır.
mysqldumpslow Kullanımı
mysqldumpslow, slow query log dosyasını özetlemek için basit ama etkili bir araçtır. Gruplandırılmış sorgu istatistikleri sunarak en sık veya en yavaş sorguları hızla belirlememizi sağlar.
mysqldumpslow -s at -t 10 /var/log/mysql/mysql-slow.logBu komut, slow query log dosyasını analiz eder ve 'ortalama sorgu zamanına' (at) göre sıralanmış en yavaş 10 sorguyu (t 10) listeler. Diğer kullanışlı sıralama seçenekleri arasında 'c' (count - tekrar sayısı), 'l' (lock time - kilitlenme süresi), 'r' (rows sent - gönderilen satır sayısı) bulunur. Çıktı, parametreleri generalize edilmiş sorgu kalıplarını ve bu kalıpların toplam yürütme sürelerini gösterir.
pt-query-digest ile Derinlemesine Analiz
pt-query-digest, mysqldumpslow'dan çok daha kapsamlı ve detaylı bir analiz sunar. Sorguların istatistiklerini (ortalama, maksimum, medyan yürütme süresi, kilit süresi vb.), execution plan ipuçlarını ve hatta sorgunun kendisini gösterir. Büyük log dosyaları ve karmaşık analizler için tercih edilen bir araçtır.
pt-query-digest /var/log/mysql/mysql-slow.log > slow_query_report.txtBu komut, slow query log dosyasını analiz eder ve detaylı bir raporu slow_query_report.txt dosyasına kaydeder. Rapor, sorguların benzersiz parmak izlerini (fingerprint), toplam sürelerini, ortalama sürelerini, çağrılma sayılarını ve hatta EXPLAIN çıktısını simüle eden bilgileri içerir. Bu sayede hangi sorgu kalıplarının en çok kaynak tükettiğini ve potansiyel indeks eksikliklerini belirlemek kolaylaşır.
İndeks Optimizasyonu: Darboğazları Giderme
Yavaş sorguları tespit ettikten sonraki adım, genellikle indeks optimizasyonudur. İndeksler, veritabanı tablolarındaki verilere hızlı erişim sağlamak için kullanılan özel bir veri yapısıdır. B-Tree, hash veya full-text gibi farklı indeks türleri bulunur.
Neden İndeksler Yavaş Sorgulara Neden Olur?
İndekslerin amacı hızlı erişim sağlamak olsa da, yanlış veya eksik indeksler sorguların daha da yavaşlamasına neden olabilir. Bir sorgunun neden yavaş çalıştığını anlamak için MySQL'in sorgu planını incelemek gerekir. Bunun için EXPLAIN komutu kullanılır.
EXPLAIN SELECT * FROM urunler WHERE kategori_id = 10 AND fiyat > 100 ORDER BY tarih DESC;EXPLAIN çıktısı, MySQL'in bir sorguyu nasıl yürüteceğini gösterir. Anahtar kolonlar şunlardır:
type: Erişim tipini gösterir (ALL, index, range, ref, eq_ref, const). ALL en kötü performans göstergesidir, tablonun tamamının taranması anlamına gelir. range, ref, eq_ref daha iyidir.key: MySQL'in sorguyu hızlandırmak için kullandığı indeksi gösterir. Eğer NULL ise indeks kullanılmıyor demektir.rows: MySQL'in sorguyu yürütmek için taramayı tahmin ettiği satır sayısını gösterir. Bu sayı ne kadar düşükse, o kadar iyi performans demektir.Extra: Ek bilgiler içerir. Örneğin, 'Using filesort' veya 'Using temporary' ifadeleri genellikle kötü performansa işaret eder ve indeks optimizasyonu gerektirir. 'Using index' ise covering index kullanıldığını ve performansın iyi olduğunu gösterir.
İndeks Oluşturma Stratejileri
İndeksler oluşturulurken aşağıdaki stratejiler göz önünde bulundurulmalıdır:
- WHERE Koşulları: Sorguların
WHEREclause'larında sıkça kullanılan sütunlara indeks eklemek en temel adımdır. - JOIN Koşulları:
JOINclause'larındaki sütunlara indeks eklemek, birleşme işlemlerinin verimliliğini artırır. - ORDER BY ve GROUP BY: Bu clause'lardaki sütunlara indeks eklemek, sıralama ve gruplama işlemlerinin disk yerine indeks üzerinde yapılmasını sağlayarak 'Using filesort' veya 'Using temporary' gibi maliyetli işlemleri engeller.
- Kompozit İndeksler: Birden fazla sütunu içeren indekslerdir. Sorgu filtreleri birden çok sütunu kapsıyorsa, bu indeksler faydalıdır. İndeksleme sırası önemlidir: en seçici (distinct değeri en çok olan) sütunlar öne gelmelidir.
- Covering İndeksler: Sorgunun ihtiyaç duyduğu tüm sütunları içeren indekslerdir. Bu durumda MySQL, tablonun kendisini okumak yerine sadece indeksi okuyarak tüm veriye ulaşabilir, bu da I/O maliyetini ciddi şekilde azaltır.
CREATE INDEX idx_kategori_fiyat_tarih ON urunler (kategori_id, fiyat, tarih DESC);Bu indeks, `kategori_id`, `fiyat` ve `tarih` sütunları üzerinde filtreleme, sıralama veya birleştirme yapan sorgular için kullanılabilir.
Gerçek Senaryo: E-ticaret Platformu Ürün Arama Performansı
Bir e-ticaret platformunda, 50 milyon ürün kaydının bulunduğu `urunler` tablosunda arama sorguları zaman zaman 5-10 saniye gibi kabul edilemez sürelerde yanıt veriyor. Slow Query Log analizimizde aşağıdaki sorgu kalıbının en çok zaman tüketenler arasında olduğunu tespit ettik:
SELECT id, isim, fiyat, resim_url FROM urunler WHERE kategori_id = 123 AND durum = 'aktif' AND fiyat BETWEEN 50 AND 200 ORDER BY populerlik DESC LIMIT 0, 20;Bu sorgunun EXPLAIN çıktısı incelendiğinde `type: ALL` ve `rows: 50M` gibi değerler görüldü. `Extra` kolonunda ise 'Using filesort' ve 'Using where' ibareleri mevcut. Bu durum, MySQL'in tablonun tamamını taradığını, koşulları her satır için kontrol ettiğini ve sonuçları diskte sıraladığını gösteriyor.
Çözüm Adımları:
- İhtiyaç Analizi: Sorgu
kategori_id,durumvefiyatüzerinde filtreleme yapıyor,populerliküzerinden sıralama yapıyor veid, isim, fiyat, resim_urlsütunlarını çekiyor. - Kompozit İndeks Oluşturma: Filtreleme ve sıralama için bir kompozit indeks gereklidir. İndeks sırası kritik. En seçici kolon (genellikle
kategori_id) ile başlayıp, eşitlik koşulları (durum), aralık koşulları (fiyat) ve son olarak sıralama koşulları (populerlik) takip edilmelidir. - Covering İndeks İçin Genişletme: Sorgu,
id, isim, fiyat, resim_urlsütunlarını da getirdiğinden, bu sütunları da indekse dahil ederek (covering index) disk I/O'sunu tamamen ortadan kaldırabiliriz.
CREATE INDEX idx_urun_arama_performans ON urunler (kategori_id, durum, fiyat, populerlik, id, isim, resim_url);Bu indeksi oluşturduktan sonra aynı sorgu tekrar çalıştırıldığında, EXPLAIN çıktısında type: range veya ref, rows değerinin önemli ölçüde düştüğü ve 'Using index' ibaresinin göründüğü tespit edildi. Sorgu süresi saniyelerden milisaniyeler seviyesine inerek platformun genel yanıt süresini kayda değer ölçüde iyileştirdi.
İndekslerin Bakımı ve Periyodik Kontroller
İndeksler oluşturulduktan sonra da periyodik bakım gerektirebilir. Özellikle yoğun INSERT/UPDATE/DELETE işlemleri gören tablolarda indeks parçalanması (fragmentation) meydana gelebilir. Bu durum, indeksin fiziksel depolamasının düzensizleşmesine ve performans düşüşüne yol açar.
ANALYZE TABLE: MySQL'in tablo istatistiklerini güncellemesini sağlar. Bu, sorgu iyileştiricinin en uygun indeksleri seçmesine yardımcı olur.OPTIMIZE TABLE: Tablonun ve indekslerinin disk üzerinde yeniden düzenlenmesini sağlar, parçalanmayı giderir ve depolama alanını optimize eder. Yoğun tablolar için dikkatli kullanılmalıdır, çünkü tablo kilitlenebilir.
Sonuç
MySQL Slow Query Log analizi ve ardından gelen indeks optimizasyonu, veritabanı performans sorunlarını çözmek için güçlü ve sistematik bir yaklaşımdır. Tespit edilen yavaş sorguların doğru indekslerle hedeflenmesi, sadece sorgu sürelerini kısaltmakla kalmaz, aynı zamanda sunucu kaynak tüketimini azaltır ve genel sistem kararlılığını artırır. Bu süreç, tek seferlik bir görev değil, veritabanı yaşam döngüsünün ayrılmaz bir parçası olarak sürekli izleme ve iyileştirme gerektiren dinamik bir çalışmadır.