MongoDB Performance Tuning: Slow Query Nasıl Optimize Edilir? 7 Teknik (2026)

01.01.2026 20:35 Haber

Yavaş sorgular ve yüksek CPU kullanımı MongoDB Performance sorunlarının başında gelir. MongoDB Performance Tuning ile database sorgularınızı 10x hızlandırabilir, server maliyetlerini %50'ye kadar azaltabilirsiniz. Alesta Web olarak production ortamlarında test edilmiş optimizasyon tekniklerini paylaşıyoruz.

MongoDB Neden Yavaş? Yaygın Sorunlar

MongoDB Performance sorunlarının %80'i şu nedenlerden kaynaklanır:

? Yaygın Performance Sorunları

Sorun Belirtiler Çözüm
Missing Indexes Query süresi > 1000ms, full collection scan Index oluşturma
Inefficient Queries Yüksek CPU, RAM kullanımı Aggregation pipeline optimize
Small WiredTiger Cache Disk I/O yüksek, page faults Cache boyutu artırma
Connection Pool Exhaustion Timeout errors, queue buildup Pool size tuning
Unoptimized Schema Çok fazla JOIN ($lookup) Embedding, denormalization
? Alesta Web İstatistiği:

Müşteri projelerinde yaptığımız MongoDB Performance Tuning sonrası ortalama iyileşmeler:

  • Query response time: %85 azalma (1200ms → 180ms)
  • CPU kullanımı: %60 azalma (80% → 32%)
  • Server maliyeti: %45 azalma (scale down mümkün oldu)

Index Optimization: En Kritik Adım

MongoDB Performance Tuning'in en kritik adımı doğru index'leri oluşturmak:

❌ Kötü Örnek: Index Yok

// users collection (5 million documents)
db.users.find({ email: "user@example.com", status: "active" })

// EXPLAIN plan:
{
  "executionStats": {
    "executionTimeMillis": 2850,  // 2.8 saniye!
    "totalDocsExamined": 5000000,  // TÜM collection scan
    "totalKeysExamined": 0,        // Index kullanılmadı
    "stage": "COLLSCAN"            // ❌ Collection scan
  }
}

✅ İyi Örnek: Compound Index

// Compound index oluştur (email + status)
db.users.createIndex({ email: 1, status: 1 })

// Aynı query tekrar çalıştır
db.users.find({ email: "user@example.com", status: "active" })

// EXPLAIN plan:
{
  "executionStats": {
    "executionTimeMillis": 12,     // 12ms! (%99.6 iyileşme)
    "totalDocsExamined": 1,        // Sadece 1 document
    "totalKeysExamined": 1,        // Index kullanıldı
    "stage": "IXSCAN"              // ✅ Index scan
  }
}

Index Stratejisi: ESR Rule

E (Equality)S (Sort)R (Range) sırası ile index oluşturun:

// Query: status=active, createdAt sırala, age aralığı
db.users.find({
  status: "active",     // Equality
  age: { $gte: 18, $lte: 65 }  // Range
}).sort({ createdAt: -1 })  // Sort

// ❌ Yanlış index sırası
db.users.createIndex({ createdAt: -1, status: 1, age: 1 })  // Verimsiz

// ✅ Doğru index (ESR rule)
db.users.createIndex({ status: 1, createdAt: -1, age: 1 })  // Optimal

// Sonuç: %70 daha hızlı query
✅ Index Best Practices:
  • Sık kullanılan query'ler için index: db.collection.getIndexes() ile kontrol
  • Compound index: Birden fazla field sorgulanıyorsa tek compound index
  • Unique index: email, username gibi unique field'lar için
  • Partial index: Sadece belirli condition'larda index (boyut tasarrufu)
  • Text index: Full-text search için (dikkatli kullanın, yavaş olabilir)

Query Optimization ve Explain Plan

MongoDB Performance analizi için explain() komutu kullanın:

Explain Plan Kullanımı

// Query performance analizi
db.orders.find({
  customerId: "12345",
  status: "pending",
  total: { $gte: 100 }
}).sort({ createdAt: -1 }).explain("executionStats")

// Key metrics:
{
  "executionTimeMillis": 45,      // Query süresi
  "totalDocsExamined": 120,       // Taranan document sayısı
  "totalKeysExamined": 120,       // Taranan index key sayısı
  "nReturned": 15,                // Dönen sonuç sayısı
  "executionStages": {
    "stage": "FETCH",             // Index + fetch
    "inputStage": {
      "stage": "IXSCAN",          // ✅ Index kullanıldı
      "indexName": "customerId_1_status_1_createdAt_-1"
    }
  }
}

// İdeal oran: totalDocsExamined ≈ nReturned (çok fazla gereksiz doc taranmamalı)

Aggregation Pipeline Optimization

// ❌ Kötü: $match en sonda
db.orders.aggregate([
  {
    $lookup: {  // 5M order + 2M customer JOIN → Çok yavaş
      from: "customers",
      localField: "customerId",
      foreignField: "_id",
      as: "customer"
    }
  },
  { $unwind: "$customer" },
  { $match: { status: "pending", "customer.country": "TR" } }  // Filter en sonda!
])
// Execution time: 8500ms ❌

// ✅ İyi: $match en başta (index kullanır)
db.orders.aggregate([
  { $match: { status: "pending" } },  // ✅ Index kullan, 5M → 50K
  {
    $lookup: {  // 50K order + 2M customer JOIN → Hızlı
      from: "customers",
      localField: "customerId",
      foreignField: "_id",
      as: "customer"
    }
  },
  { $unwind: "$customer" },
  { $match: { "customer.country": "TR" } }  // Final filter
])
// Execution time: 320ms ✅ (%96 iyileşme)
⚠️ Aggregation Best Practices:

Alesta Web production deneyimleri:

  1. $match ilk stage olmalı: Index kullanımı, data miktarını azaltır
  2. $project gereksiz field'leri hemen at: Memory kullanımı azalır
  3. $lookup dikkatli kullan: JOIN pahalı, mümkünse embedding tercih et
  4. $sort + $limit birlikte: MongoDB optimize eder (top-K sort)
  5. allowDiskUse: true: Büyük aggregation'larda memory aşımını önler

Schema Design Best Practices

MongoDB Performance Tuning için schema design kritik:

Embedding vs Referencing

// ❌ Kötü: Her query JOIN gerektirir (yavaş)
// users collection
{
  _id: ObjectId("..."),
  name: "John Doe",
  email: "john@example.com"
}

// orders collection (1M documents)
{
  _id: ObjectId("..."),
  userId: ObjectId("..."),  // Reference
  items: [...],
  total: 250
}

// Her order query $lookup gerektirir:
db.orders.aggregate([
  { $match: { _id: ObjectId("...") } },
  {
    $lookup: {
      from: "users",
      localField: "userId",
      foreignField: "_id",
      as: "user"
    }
  }
])
// Execution time: 45ms (her seferinde JOIN)

// ✅ İyi: Embedding (1-to-few relationship)
// orders collection
{
  _id: ObjectId("..."),
  user: {  // Embedded document
    _id: ObjectId("..."),
    name: "John Doe",
    email: "john@example.com"
  },
  items: [...],
  total: 250
}

// Tek query, JOIN yok:
db.orders.findOne({ _id: ObjectId("...") })
// Execution time: 2ms (%95 iyileşme)

Array Size Optimization

// ❌ Kötü: Sınırsız array growth (16MB document limit)
{
  _id: ObjectId("..."),
  productId: "12345",
  reviews: [  // 10,000+ review → Document çok büyük
    { user: "...", rating: 5, comment: "..." },
    { user: "...", rating: 4, comment: "..." },
    // ... 10,000 more
  ]
}
// Problem: Document > 16MB → Error, query çok yavaş

// ✅ İyi: Separate collection (1-to-many)
// products collection
{
  _id: ObjectId("..."),
  name: "Product Name",
  avgRating: 4.5,
  reviewCount: 10000
}

// reviews collection (ayrı)
{
  _id: ObjectId("..."),
  productId: ObjectId("..."),  // Index!
  user: "...",
  rating: 5,
  comment: "..."
}

// Index oluştur:
db.reviews.createIndex({ productId: 1, createdAt: -1 })

// Query (sayfalama ile):
db.reviews.find({ productId: ObjectId("...") })
  .sort({ createdAt: -1 })
  .limit(20)
  .skip(0)
// Hızlı ve scalable

Connection Pool Tuning

MongoDB Performance için connection pool ayarları önemli:

Node.js MongoDB Driver (Mongoose)

// ❌ Kötü: Default settings (production için yetersiz)
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/mydb');
// Default: maxPoolSize=100, minPoolSize=0

// Problem: High traffic'te connection exhaustion

// ✅ İyi: Production-ready settings
mongoose.connect('mongodb://localhost:27017/mydb', {
  maxPoolSize: 200,          // Max connections (server kapasitesine göre)
  minPoolSize: 50,           // Min connections (always ready)
  maxIdleTimeMS: 30000,      // Idle connection timeout
  serverSelectionTimeoutMS: 5000,
  socketTimeoutMS: 45000,
  family: 4                  // IPv4 kullan (faster DNS)
});

// Connection pool monitoring
mongoose.connection.on('open', () => {
  console.log('MongoDB connected, pool ready');
});

// Alesta Web production: 200 max pool, 1000 req/s → %0 timeout

Python PyMongo

# ❌ Kötü: Default pool settings
from pymongo import MongoClient
client = MongoClient('mongodb://localhost:27017/')
# Default: maxPoolSize=100

# ✅ İyi: Optimized pool
client = MongoClient(
    'mongodb://localhost:27017/',
    maxPoolSize=300,        # Max connections
    minPoolSize=50,         # Min connections
    maxIdleTimeMS=30000,
    serverSelectionTimeoutMS=5000,
    connectTimeoutMS=10000,
    retryWrites=True        # Automatic retry on network errors
)

# Connection pool stats
client.server_info()  # Verify connection
print(f"Active connections: {client.nodes}")

# Alesta Web Django app: 300 max pool, FastAPI async → 2500 req/s

WiredTiger Cache Configuration

MongoDB Performance Tuning için WiredTiger cache optimize edin:

mongod.conf Optimization

# /etc/mongod.conf - Production settings
storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
    commitIntervalMs: 100  # Default 100ms, write performance
  engine: wiredTiger
  wiredTiger:
    engineConfig:
      # Cache size: 50% of RAM (default) → 70% için override
      cacheSizeGB: 14  # 20GB RAM sunucuda 14GB cache
      journalCompressor: snappy  # zlib → snappy (daha hızlı)
      directoryForIndexes: true  # Index'leri ayrı klasörde
    collectionConfig:
      blockCompressor: snappy  # Default, hızlı compression
    indexConfig:
      prefixCompression: true  # Index compression (disk tasarrufu)

# Network settings
net:
  port: 27017
  bindIp: 127.0.0.1  # Localhost only (production'da private IP)
  maxIncomingConnections: 65536  # Default 65536, yeterli

# Operation profiling
operationProfiling:
  mode: slowOp
  slowOpThresholdMs: 100  # 100ms+ query'leri logla

# Restart MongoDB
# sudo systemctl restart mongod
✅ WiredTiger Tuning Sonuçları:

Alesta Web müşteri projesi (20GB RAM server):

  • Öncesi: cacheSizeGB=10 (default 50%) → Disk I/O yüksek
  • Sonrası: cacheSizeGB=14 (70%) → %65 disk I/O azalması
  • Query latency: P95 480ms → 120ms (%75 iyileşme)

Sharding ve Horizontal Scaling

Çok büyük database'ler için MongoDB Performance çözümü sharding:

Sharding Nedir?

Data'yı birden fazla server'a (shard) böler, parallel query yapılır:

// Sharding setup (simplified)
// 1. Config server cluster başlat
mongod --configsvr --replSet configReplSet --port 27019

// 2. Shard servers başlat
mongod --shardsvr --replSet shard1 --port 27018
mongod --shardsvr --replSet shard2 --port 27028

// 3. mongos router başlat
mongos --configdb configReplSet/localhost:27019 --port 27017

// 4. Shard'ları ekle
sh.addShard("shard1/localhost:27018")
sh.addShard("shard2/localhost:27028")

// 5. Database sharding aktif et
sh.enableSharding("mydb")

// 6. Collection shard key belirle
sh.shardCollection("mydb.orders", { customerId: "hashed" })

// Sonuç: 100M document'i 2 shard'a böldü → 2x query speed
⚠️ Sharding Dikkat Noktaları:

Alesta Web production deneyimi:

  • Shard key seçimi kritik: Homojen dağılım sağlamalı (hashed keys ideal)
  • $lookup cross-shard yavaş: Mümkünse embedding kullanın
  • Operational complexity artar: Backup, monitoring daha karmaşık
  • Minimum 3 config server: High availability için
  • Sharding < 100GB gereksiz: Önce index + schema optimize edin

Performance Monitoring Tools

MongoDB Performance Tuning sürekli monitoring gerektirir:

MongoDB Atlas Performance Advisor

Managed MongoDB Atlas kullanıyorsanız, built-in Performance Advisor index önerileri sunar:

// Atlas Console → Performance Advisor
// Önerilen index'leri gösterir:

// Örnek öneri:
{
  "namespace": "mydb.users",
  "index": { "email": 1, "status": 1 },
  "impact": "High",
  "avgExecutionTime": "1250ms",
  "suggestedExecutionTime": "15ms"
}

// Tek tıkla index oluşturabilirsiniz

MongoDB Profiler (Self-hosted)

// Profiler aktif et (slow queries logla)
db.setProfilingLevel(1, { slowms: 100 })

// Slow query'leri analiz et
db.system.profile.find({ millis: { $gt: 100 } })
  .sort({ ts: -1 })
  .limit(10)
  .pretty()

// Örnek slow query:
{
  "op": "query",
  "ns": "mydb.orders",
  "command": { "find": "orders", "filter": { "status": "pending" } },
  "millis": 1250,
  "planSummary": "COLLSCAN",  // ❌ Index yok!
  "ts": ISODate("2026-01-01T12:00:00Z")
}

// Çözüm: Index oluştur
db.orders.createIndex({ status: 1 })

Prometheus + Grafana Monitoring

# docker-compose.yml - MongoDB monitoring stack
version: '3.8'
services:
  mongodb:
    image: mongo:7
    ports:
      - "27017:27017"

  mongodb-exporter:
    image: percona/mongodb_exporter:0.40
    command:
      - '--mongodb.uri=mongodb://mongodb:27017'
      - '--collect-all'
    ports:
      - "9216:9216"

  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin

# Key metrics to monitor:
# - Query execution time (p95, p99)
# - Connection pool usage
# - WiredTiger cache hit ratio
# - Disk I/O
# - CPU usage

✅ Özet: MongoDB Performance Tuning

MongoDB Performance Tuning ile query sürelerini %90+ azaltmak mümkün. En kritik adımlar: Index optimization (ESR rule), aggregation pipeline $match önceliklendirme, WiredTiger cache tuning (%70 RAM), schema design (embedding vs referencing).

Hızlı Kontrol Listesi:

  • ✅ Tüm sık kullanılan query'lerde index var mı?
  • ✅ Explain plan IXSCAN gösteriyor mu (COLLSCAN değil)?
  • ✅ Aggregation pipeline $match ilk stage'de mi?
  • ✅ WiredTiger cache %60-70 RAM kullanıyor mu?
  • ✅ Connection pool high traffic'i handle ediyor mu?
  • ✅ Slow query profiler aktif mi (>100ms)?

Faydalı Kaynaklar:

© 2026 Alesta Web - MongoDB performance ve database optimization uzmanınız. Tüm hakları saklıdır.

WM Tools
💫

WebMaster Tools

15 Profesyonel Araç