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.
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
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
JOINkullanın veyaIN (...)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
connectionLimitdeğ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
OFFSETyerineseek method(keyset pagination) kullanarak performansı artırın.