Yazılarımız

Veri Akademi

MONGODB INDEXİNG VE AGGREGATİON PİPELİNE: PERFORMANS ODAKLI REHBER

MongoDB tarafında performans sorunlarının büyük bölümü iki yerde düğümlenir: yanlış veya eksik index stratejisi ve amacını aşan aggregation pipeline tasarımları. “Çalışıyor” olması çoğu zaman yetmez; veri büyüdükçe aynı sorgu, dakikalara uzayan gecikmelere dönüşebilir.

Bu rehber, indexing ve aggregation pipeline’ı birlikte düşünerek, sorgu sürelerini düşürmenin ve kaynak tüketimini kontrol altında tutmanın pratik yollarını anlatır. Hedefimiz, “hangi index’i açmalıyım?” sorusunu iş yükü ve sorgu şekli üzerinden yanıtlamak; pipeline’ı da aynı mantıkla sadeleştirip akıllıca sıralamak.

Okurken her bölümde, önce mantığı kuracak; sonra explain ve gerçekçi örneklerle “neden böyle?” sorusunu görünür hâle getireceğiz. Ayrıca, ileri seviye optimizasyonlarda sık yapılan hatalara ve bunların etkilerine de değineceğiz.


Primary Keyword: MongoDB indexing ve aggregation pipeline performansı

Bu makalenin ana odağı, MongoDB indexing ve aggregation pipeline performansını birlikte ele almak. Çünkü pipeline ne kadar iyi kurgulanırsa kurgulansın, yanlış index seçimi yüzünden koleksiyon taraması (COLLSCAN) yapılırsa sonuç kaçınılmaz şekilde yavaşlar. Tersi de geçerli: harika index’leriniz olsa bile, gereksiz stage’ler ve yanlış sıralama kaynak tüketimini patlatabilir.

Indexing Neden Hâlâ Birinci Öncelik?

Seçicilik ve kardinaliteyi doğru okumak

Index’in temel görevi, aradığınız kayıtları olabildiğince küçük bir aralıkta bulmanızı sağlamak. Burada kritik kavram seçicilik: bir alanın farklı değer sayısı ne kadar fazlaysa, o alan üzerinden filtrelemek o kadar avantajlıdır. Örneğin “status” alanı 3–4 değer taşıyorsa tek başına index olarak çoğu senaryoda sınırlı katkı sağlar; buna karşılık “userId”, “email” veya “orderNo” gibi yüksek kardinaliteli alanlar filtreyi daraltır.

Bir index’i tasarlarken, en sık gelen sorguların filtre alanlarını, sıralama (sort) ihtiyaçlarını ve projeksiyon (projection) davranışını birlikte düşünmek gerekir. Aksi durumda, index var gibi görünür ama planlayıcı (query planner) onu seçmeyebilir.

Compound index sıralaması: filtre, eşitlik, aralık, sıralama

MongoDB’de compound index tasarımında alan sırası önemlidir. Genel bir pratik yaklaşım: önce eşitlik filtreleri (equalities), sonra aralık filtreleri (ranges), ardından sort ihtiyacı. Örneğin bir rapor ekranı “tenantId = X” ve “createdAt arasında” filtreleyip “createdAt desc” sıralıyorsa, { tenantId: 1, createdAt: -1 } çoğu durumda güçlü bir başlangıçtır.

  • Eşitlik filtreleri (tenantId, userId gibi) index başına taşınır.
  • Aralık (createdAt, price gibi) genellikle ikinci/üçüncü sıraya gelir.
  • Sort ihtiyacı, aralık sonrası doğru yönde eklenirse ek bir sıralama maliyeti düşebilir.

Aggregation Pipeline Mimarisi: Stage Sıralaması Performansı Belirler

Erken filtre, erken daraltma: $match ve $project

Aggregation pipeline’da en büyük kazanım genellikle en baştan gelir: veriyi daha erken daraltırsanız, sonraki stage’ler daha az dokümanla çalışır. Bu yüzden $match ve gerekli alanları seçen $project stage’lerini mümkün olduğunca öne taşımak iyi bir pratiktir. Özellikle büyük dokümanlarda, gereksiz alanları taşımak ağ ve bellek maliyetini artırır.

$sort ve $limit ilişkisi: top-N kuralı

Birçok senaryoda kullanıcı “en güncel 20 kayıt” ister. Pipeline’da önce $sort sonra $limit kullanmak doğrudur; ancak bu operasyonun maliyeti, sort alanının index’lenip index üzerinden çözülebilmesine bağlıdır. Index yoksa MongoDB bellek kullanır; yetmezse disk’e taşabilir. Bu yüzden top-N senaryolarında, sort alanını doğru compound index içine almak büyük fark yaratır.

$lookup ve join maliyeti: veri modeli gerçeği

$lookup güçlüdür ama “her yerde join yaparım” yaklaşımı pahalıya patlar. Özellikle eşleşen taraf büyükse, pipeline süresi hızla uzar. Çoğu durumda, ilişkiyi tersine çevirerek veya önceden hesaplanmış özet koleksiyonlar kullanarak maliyeti düşürmek mümkündür. Yine de $lookup kaçınılmazsa, join anahtarlarında uygun index ve pipeline içi filtreleme şarttır.

Index alanları ve pipeline adımlarının veri akışını nasıl daralttığını gösteren performans odaklı yapı

Index + Pipeline Birlikte Optimize Edilir

$match stage’ini index’le “beslemek”

Pipeline’daki ilk $match, normal find() sorgusu gibi index kullanabilir. Bu yüzden, raporlarınız veya API uçlarınız için en kritik filtre kombinasyonlarını belirleyip bunlara uygun compound index’ler açmak gerekir. Ayrıca $match’in index kullanabilmesi için, filtrelerin stage içinde mümkün olduğunca basit ve doğrudan olması önemlidir.

Covered query mantığını aggregation’a taşımak

Covered query, sorgunun sadece index’ten karşılanması demektir; dokümanın kendisine gidilmez. Aggregation tarafında bunun tam karşılığı her zaman bire bir değildir, fakat aynı fikri destekleyen yaklaşım şudur: erken $project ile ihtiyacınız olmayan alanları elemek ve mümkün olduğunca küçük “işleyen veri” hacmiyle devam etmek. Bu, özellikle sayfalama ve raporlama senaryolarında ciddi fark yaratır.

Örnek: Sipariş raporu için index ve pipeline

Senaryo: Çok kiracılı (multi-tenant) bir sistemde, bir tenant’ın belirli tarih aralığındaki tamamlanan siparişleri listeleniyor; kullanıcı son 50 kaydı, toplam tutar ve ödeme yöntemi dağılımıyla birlikte görmek istiyor. Burada hem listeleme hem özetleme olduğu için pipeline tasarımı kritik.

// Önerilen index (listeleme + tarih aralığı + status)
db.orders.createIndex({ tenantId: 1, status: 1, createdAt: -1 });

// Sorgu/pipeline
db.orders.aggregate([
  { $match: {
      tenantId: "t_1001",
      status: "COMPLETED",
      createdAt: { $gte: ISODate("2025-12-01T00:00:00Z"), $lt: ISODate("2026-02-01T00:00:00Z") }
  }},
  { $project: { _id: 1, createdAt: 1, total: 1, paymentMethod: 1, customerId: 1 } },
  { $sort: { createdAt: -1 } },
  { $limit: 50 },
  { $group: {
      _id: "$paymentMethod",
      count: { $sum: 1 },
      totalAmount: { $sum: "$total" }
  }},
  { $sort: { totalAmount: -1 } }
]);

Bu örnekte, ilk $match’in index’ten beslenmesi hedeflenir. $project ile doküman şişkinliği azaltılır. $sort + $limit ikilisi “top-N” mantığıyla çalışır; doğru index yoksa bu aşama bellek/disk maliyeti üretir. Sonrasında $group ve ikinci $sort, özet veriyi düzenler.

Explain Plan Okuma: “Çalışıyor” Yetmez, Nasıl Çalışıyor?

COLLSCAN, IXSCAN ve kazanımın görünür hâli

Performans iyileştirmenin ilk adımı ölçmektir. MongoDB’de bunun en pratik aracı explain plan’dır. Basit bir find() için explain(), aggregation için explain("executionStats") yaklaşımı size gerçek çalışma biçimini gösterir. Aradığınız sinyaller:

  1. COLLSCAN görüyorsanız, index ihtiyacı veya yanlış sorgu şekli vardır.
  2. IXSCAN ve düşük “keysExamined/docsExamined” oranı, iyi bir işarettir.
  3. Sort aşamasında büyük bellek kullanımı, index’le çözülebilecek bir sıralama ihtiyacına işaret eder.

Örnek: Aggregation için executionStats

db.orders.explain("executionStats").aggregate([
  { $match: { tenantId: "t_1001", status: "COMPLETED" } },
  { $sort: { createdAt: -1 } },
  { $limit: 20 },
  { $project: { createdAt: 1, total: 1 } }
]);

Bu çıktıda “totalKeysExamined” ve “totalDocsExamined” değerleri, index’in işe yarayıp yaramadığını doğrudan gösterir. Ayrıca “executionTimeMillis” sadece tek başına anlamlı değildir; farklı veri boyutlarında trendi takip etmek daha sağlıklıdır. İzleme tarafında, aynı sorgunun farklı zamanlarda nasıl davrandığını kıyaslamak, bir regresyonu yakalamanın en hızlı yoludur.

Execution stats çıktısında keysExamined ve docsExamined oranının sorgu maliyetini yorumlamaya yardımcı olması

İleri Optimizasyonlar: Partial, Sparse, TTL ve Text Index

Partial index ile “sadece gereken” veriyi index’lemek

Her şeyi index’lemek, her zaman iyi fikir değildir. Index, yazma maliyeti ve disk kullanımı getirir. Sadece belirli bir alt kümeye sık erişiyorsanız, partial index avantaj sağlar. Örneğin sadece “ACTIVE” kullanıcılar üzerinde arama yapıyorsanız, filtre şartıyla index’i küçültebilirsiniz. Bu, özellikle büyük koleksiyonlarda performans ve maliyet dengesini iyileştirir.

TTL index ile yaşam döngüsü yönetimi

Log, oturum veya geçici veriler için TTL index, veri temizliğini otomatikleştirir. Böylece koleksiyon şişmesini önler, sorguların taradığı veri hacmini azaltır. Ancak TTL’nin “anlık” değil periyodik çalıştığını bilmek gerekir; bu yüzden SLA beklentinizi doğru kurmalısınız.

Text index ve arama gereksinimi

MongoDB text index, basit arama ihtiyaçlarında faydalı olabilir; ancak gelişmiş arama (dil analizleri, sıralama stratejileri, fuzzy) için farklı çözümler gerekebilir. Yine de sisteminizde arama kurgusu varsa, text index’in yazma ve disk maliyetini dikkate alarak konumlandırmak gerekir. Alternatif olarak, sık kullanılan arama sonuçlarını özet koleksiyonlarda tutmak, uygulama düzeyinde önbelleklemek gibi stratejiler de değerlidir.

$lookup ve $unwind: İlişkisel Model Beklentisini Kontrol Et

Pipeline içi filtreleme ile join hacmini düşürmek

$lookup sonrası gelen dokümanlar çok büyükse, $unwind ile patlayabilir ve performansı dramatik biçimde düşürebilir. İdeal yaklaşım, mümkünse $lookup içinde pipeline kullanarak eşleşen tarafı filtrelemek ve sadece gerekli alanları çekmektir. Böylece join çıktısı küçülür, sonraki stage’ler daha az yük taşır.

Özet koleksiyonlar ile raporlama yükünü ayırmak

Gerçek zamanlı raporlar, büyük koleksiyonlar üzerinde ağır pipeline’lar koştuğunda sistemi kilitleyebilir. Bu tür senaryolarda, gün sonu/belirli aralıklarla hesaplanan özet koleksiyonlar (materialized view benzeri) ciddi rahatlama sağlar. Örneğin günlük tenant bazlı satış toplamı, ödeme yöntemi dağılımı gibi metrikler ayrı koleksiyonda tutulabilir. Bu yaklaşım, API yanıt sürelerini daha stabil hâle getirir.

Lookup ile birleştirme yapılan koleksiyonlarda join anahtarlarının index’lenmesiyle sorgu süresinin kısalması

Performans İzleme ve Operasyonel Kontroller

Yavaş sorgu günlükleri ve eşik belirleme

Üretim ortamında performans sorunları genellikle “ani” görünür, ama çoğu zaman yavaş yavaş birikir. Bu yüzden yavaş sorgu eşiği belirlemek, log’ları düzenli takip etmek ve en pahalı sorguları biriktirmek önemlidir. Önemli olan, tek seferlik hızlandırmalar değil; iş yükü değiştikçe sürdürülebilir performans sağlamaktır.

Yazma yükü altında index maliyeti

Index sayısı arttıkça insert/update maliyeti artar. Bu nedenle “her rapor için index” yaklaşımı zamanla yazma performansını düşürür. En doğru denge, gerçek sorgu istatistiklerine göre, en çok kullanılan sorgulara odaklanmak ve nadir raporları ya özet koleksiyonlara taşımak ya da zaman planlı (off-peak) çalıştırmaktır. Özellikle çok yüksek yazma oranı olan sistemlerde, index değişikliklerinin kontrollü yapılması gerekir.

Sık Yapılan Hatalar ve Hızlı Kontrol Listesi

Hata 1: Tek alan index ile her şeyi çözmeye çalışmak

Tek alan index çoğu zaman başlangıç için iyidir; fakat filtre + sort birlikte kullanılıyorsa compound index kaçınılmazdır. “Index var ama yine yavaş” şikâyeti çoğunlukla bu nedenle ortaya çıkar.

Hata 2: Pipeline’da $match’i geç koymak

$match’i sona yakın koymak, önce gereksiz şekilde büyük veri işlemek anlamına gelir. Bu, bellek kullanımını ve CPU süresini artırır. Mümkün olan en erken noktada daraltma hedeflenmelidir.

Hata 3: $lookup ile aşırı geniş doküman çekmek

Join tarafında sadece gereken alanları çekmemek, ağı ve belleği şişirir. Pipeline içi projeksiyon ve filtreleme ile join çıktısını küçültmek çoğu zaman en kolay kazançtır.

  • Sorgu şekillerini çıkarın: en sık 10–20 sorgu deseni
  • Her desen için “filter + sort + projection” üçlüsünü not edin
  • Explain ile COLLSCAN/IXSCAN karşılaştırması yapın
  • Index sayısını yazma yüküyle birlikte değerlendirin
  • Rapor yükü artıyorsa özet koleksiyon yaklaşımını düşünün

Öğrenmeyi Derinleştirmek: Eğitim Kaynağı

Index ve aggregation optimizasyonunu daha sistematik ele almak, gerçek vakalarda explain yorumlamak ve veri modeli kararlarını doğru vermek istiyorsanız, kapsamlı bir içerik için MongoDB Eğitimi sayfasına göz atabilirsiniz. Böylece sadece tekil sorguları değil, bütün bir mimariyi performans odaklı kurgulama pratiği kazanırsınız.


Sonuç olarak, MongoDB performansı bir “tek ayar” meselesi değildir. Indexing sorgu erişimini hızlandırır; aggregation pipeline ise işleme maliyetini belirler. İkisini birlikte tasarladığınızda, büyüyen veri hacminde bile yanıt sürelerini daha tutarlı tutabilir, kaynak tüketimini daha öngörülebilir hâle getirebilirsiniz.

 VERİ AKADEMİ