MySQL Slow Query Log Analizi ve Optimizasyon

Node.js ve MySQL: Slow Query Log Analizi ile Performans Optimizasyonu

Node.js uygulamalarında performans darboğazlarının en yaygın sebebi, asenkron yapının doğası gereği bloklanmayan Event Loop değil, veritabanı katmanındaki yavaş yanıt süreleridir. Bu rehberde, MySQL Slow Query Log özelliğini kullanarak yavaş sorguları nasıl tespit edeceğinizi, mysql2 kütüphanesi ile Node.js tarafında bu süreci nasıl izleyeceğinizi ve derinlemesine optimizasyon tekniklerini inceleyeceğiz.

Not: Node.js tek iş parçacıklı (single-threaded) bir yapıya sahip olsa da, veritabanı sürücüleri I/O işlemlerini arka planda yönetir. Ancak yavaş bir sorgu, veritabanı bağlantı havuzunu (connection pool) tüketerek uygulamanın genel yanıt süresini (latency) dramatik şekilde artırabilir.

1. MySQL Slow Query Log Yapılandırması

Yavaş sorguları analiz etmenin ilk adımı, MySQL sunucusunda bu özelliği aktif etmektir. Belirli bir saniyenin (veya milisaniyenin) üzerinde süren tüm sorgular bu log dosyasına kaydedilir.

MySQL Yapılandırma Parametreleri

Aşağıdaki komutları MySQL CLI üzerinden çalıştırarak veya my.cnf (veya my.ini) dosyasına ekleyerek özelliği aktif edebilirsiniz:

-- Slow Query Log'u aktif et
SET GLOBAL slow_query_log = 'ON';

-- 1 saniyeden uzun süren sorguları kaydet (0.5 gibi ondalık değerler verilebilir)
SET GLOBAL long_query_time = 1.0;

-- İndeks kullanmayan sorguları da logla
SET GLOBAL log_queries_not_using_indexes = 'ON';

-- Log dosyasının konumunu belirle
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow-query.log';

2. Node.js Tarafında Sorgu Sürelerini İzleme

MySQL loglarına ek olarak, uygulama seviyesinde hangi sorgunun ne kadar sürdüğünü takip etmek, uygulama bağlamını (context) anlamak açısından kritiktir. mysql2 kütüphanesi kullanarak basit bir wrapper oluşturabiliriz.

Pratik Örnek: Query Execution Timer

const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  database: 'test_db',
  waitForConnections: true,
  connectionLimit: 10
});

async function trackedQuery(sql, params) {
  const start = Date.now();
  try {
    const [rows] = await pool.execute(sql, params);
    const duration = Date.now() - start;
    
    if (duration > 500) { // 500ms üzerindeyse uyar
      console.warn(`[Slow Query Warning] Duration: ${duration}ms | SQL: ${sql}`);
    }
    
    return rows;
  } catch (error) {
    throw error;
  }
}

// Kullanım
(async () => {
  const users = await trackedQuery('SELECT * FROM orders WHERE total_amount > ?', [1000]);
})();

3. Slow Query Log Analiz Araçları

Log dosyası büyüdüğünde manuel olarak okumak imkansız hale gelir. Bu noktada profesyonel analiz araçları devreye girer.

mysqldumpslow Kullanımı

MySQL ile birlikte gelen bu araç, benzer sorguları gruplayarak en çok kaynak tüketenleri listeler:

# En çok zaman alan 10 sorguyu listele
mysqldumpslow -s t -t 10 /var/log/mysql/slow-query.log

# En çok satır döndüren sorguları listele
mysqldumpslow -s r -t 10 /var/log/mysql/slow-query.log
Profesyonel İpucu: Daha detaylı analiz için Percona Toolkit içerisinde yer alan pt-query-digest aracı, sorguların grafiksel dağılımını ve etki analizini sunar.

4. EXPLAIN ile Sorgu Analizi ve Optimizasyon

Yavaş bir sorgu tespit edildiğinde, MySQL'in bu sorguyu nasıl çalıştırdığını anlamak için EXPLAIN komutu kullanılır. Node.js geliştiricileri için bu çıktıdaki kritik alanlar şunlardır:

Alan Anlamı İdeal Değer
type Tablo tarama yöntemi const, eq_ref, ref (ALL'dan kaçının)
rows İncelenen tahmini satır sayısı Mümkün olduğunca düşük
key Kullanılan indeks NULL olmamalı
Extra Ek bilgiler Using filesort veya Using temporary varsa dikkat!

Örnek İyileştirme Senaryosu

Yavaş Sorgu: SELECT * FROM products WHERE category_id = 5 ORDER BY created_at DESC;

Eğer category_id üzerinde indeks yoksa, MySQL tüm tabloyu tarar (Full Table Scan). Çözüm olarak "Composite Index" eklenmelidir:

-- Hem filtreleme hem sıralama için optimize edilmiş indeks
ALTER TABLE products ADD INDEX idx_category_created (category_id, created_at);

5. Node.js Best Practices ve Performans İpuçları

  • N+1 Probleminden Kaçının: Döngü içerisinde veritabanı sorgusu atmak yerine JOIN kullanın veya IN (...) operatörü ile toplu veri çekin.
  • Connection Pool Yönetimi: Bağlantıları her sorguda açıp kapatmak yerine bir havuz (pool) kullanın ve connectionLimit değerini sunucu kapasitesine göre ayarlayın.
  • Sadece Gereken Sütunları Seçin: SELECT * yerine sadece ihtiyacınız olan sütunları (SELECT id, name) çağırarak I/O ve bellek yükünü azaltın.
  • Pagination (Sayfalama): Büyük veri setlerinde OFFSET yerine seek method (keyset pagination) kullanarak performansı artırın.
Sonuç: MySQL Slow Query Log analizi, Node.js uygulamanızın ölçeklenebilirliği için bir lüks değil, zorunluluktur. Düzenli log analizi ve doğru indeksleme stratejileri ile yanıt sürelerinizi %90'a varan oranlarda iyileştirebilirsiniz.