MONGODB SCHEMA DESIGN ANTI-PATTERNS
"MongoDB schemaless'tır, şema diye bir derdim yok" — bu cümleyi söyleyen geliştirici, çoğu zaman altı ay sonra performans düşüşü ve disk şişmesiyle geri döner. MongoDB'nin esnek doküman modeli "şema yok" anlamına gelmez; şema kararını uygulama katmanına ittiği anlamına gelir. Bu farkı kavramadan tasarlanan koleksiyonlar; sorgu zamanında patlayan dokümanlar, sınırsız büyüyen diziler ve gereksiz $lookup yığınları üretir. Aşağıda en sık karşılaşılan anti-pattern'leri ve bunlardan nasıl kaçınılacağını ele alıyoruz.
Schemaless Yanılgısı Nereden Geliyor?
MongoDB'nin pazarlama söylemi yıllarca "esnek şema" üzerinden ilerledi ve geliştiricilerin bir kısmı bunu "şema tasarlamadan kod yazabilirim" olarak okudu. Oysa esnek şema; alan ekleyip çıkarırken migration zorunluluğu olmaması anlamına gelir, kararı atlamak değil. Doküman yapısı yine de sorgu desenlerine, yazma sıklığına ve büyüme şekline göre seçilmek zorundadır.
İlişkisel dünyadan gelen geliştiricilerde sık görülen bir refleks de tam tersi yönde işler: her şeyi normalize etmek. MongoDB'de her sorguda $lookup zinciri kurmak, RDBMS'teki JOIN'in ucuz olduğu varsayımının doküman veritabanına yanlış taşınmasıdır. MongoDB'nin felsefesi "birlikte erişilen veri birlikte saklanır" üzerine kuruludur.
Embedded vs Referenced — Doğru Karar Nasıl Verilir?
Bu kararı verirken üç temel soru sorulur:
- Birlikte mi okunuyor? Eğer alt veri ana doküman ile %90+ oranda birlikte sorgulanıyorsa embed edilir.
- Sınırlı mı büyüyor? Alt veri sayısı öngörülebilir bir üst sınıra sahipse (örn. bir siparişin kalemleri) embed güvenlidir.
- Bağımsız güncelleniyor mu? Alt veri sık ve tek başına güncelleniyorsa, ana dokümanı her seferinde dolaşmak yerine referans tercih edilir.
Örnek: Bir blog yazısı ile yorumları. Yorumlar 5-50 arası kalıyorsa embed; bir gönderi viral olup binlerce yorum alabiliyorsa ayrı koleksiyon + reference tercih edilir. Karar, ortalama vakaya değil en kötü vakaya göre verilir. Embed ve reference seçimini belirleyen erişim desenleri ile büyüme sınırları üzerine resmi modelleme dokümantasyonunda ek senaryolar ve karar kriterleri yer alır.

Unbounded Array — En Pahalı Hata
Anti-pattern listesinin başında "sınırsız büyüyen dizi" gelir. Tipik senaryo şudur: kullanıcı dokümanına activityLog dizisi eklenir, her olay buraya push edilir. İlk haftalar sorun çıkmaz. Altıncı ayda doküman 8 MB'a ulaşır, BSON limiti olan 16 MB'a yaklaşır, sorgu zamanları katlanır.
Unbounded array'in yarattığı somut problemler:
- Doküman büyüdükçe in-place update imkânsızlaşır, MongoDB dokümanı taşımak zorunda kalır.
- Tek bir alan için bile dokümanın tamamı belleğe yüklenir — working set şişer.
- Dizi üzerindeki index'ler çok değerli (multikey) hale gelir, kardinalite patlar.
- 16 MB BSON limitine dayanan doküman, ileride bütün uygulamayı kilitleyebilir.
Çözüm yaklaşımları: bucket pattern ile dizileri sabit boyutlu paketlere bölmek, outlier pattern ile sıra dışı büyüyen kayıtları ayrı koleksiyona taşımak ya da kalemleri en baştan ayrı bir koleksiyona referans olarak yazmak. MongoDB tasarımının temellerini ve bu desenlerin pratik uygulamasını daha derinlemesine öğrenmek için MongoDB Eğitimi içeriğinden yararlanabilirsiniz.
Massive Number of Collections
İkinci sık görülen anti-pattern: her kullanıcıya, her müşteriye, her güne ayrı bir koleksiyon açmak. "user_1234_logs" tarzı isimlendirme RDBMS dünyasında tablo izolasyonu gibi cazip görünür ama MongoDB'de WiredTiger her koleksiyon için ayrı dosya tutar. On binlerce koleksiyon; dosya tanımlayıcı tükenmesi, cache parçalanması ve yedekleme süresi patlaması demektir.
Doğru yaklaşım: tek koleksiyon + iyi index'lenmiş ayırıcı alan (tenantId, userId). Sharding gerekirse bu alan zaten shard key adayıdır.
Bloated Documents ve Gereksiz Alanlar
Her dokümana her ihtimale karşı 40 alan koymak, MongoDB'nin esnekliğini yanlış okumaktır. Hiç kullanılmayan alanlar bile her okumada ağ üzerinden taşınır, belleği işgal eder. Projection ile alanları kırpmak palyatif çözümdür — asıl mesele şemayı sorgu desenlerine göre yalın tutmaktır.
Pratik kural: bir alan dokümanların %10'undan azında anlamlı değer içeriyorsa, o alan için ayrı bir alt-doküman ya da koleksiyon düşünülmelidir.
Separating Data That Is Accessed Together
RDBMS refleksiyle gelen geliştiriciler, mantıksal olarak ayrı görünen veriyi farklı koleksiyonlara koyar ve her sorguda $lookup çalıştırır. Aggregation pipeline'da $lookup, doküman başına ekstra disk erişimi demektir; binlerce dokümanlık bir sorguda performans 10-100x arası düşebilir. Birlikte okunan veri — örneğin ürün ile o ürünün öne çıkan fiyat/stok bilgisi — aynı dokümanda tutulmalıdır.

Anti-Pattern'leri Erken Yakalama
MongoDB Atlas'ın Performance Advisor ve Schema Anti-Patterns sekmesi, koleksiyonlarınızdaki sorunları doküman boyutu, dizi büyüklüğü ve koleksiyon sayısı üzerinden raporlar. Self-hosted ortamlarda db.collection.stats() çıktısındaki avgObjSize ve storageSize değerleri ilk işaret fişeğidir. 100 KB'ı geçen ortalama doküman boyutu, 1000'i aşan dizi uzunlukları ya da yüzlerce koleksiyon — hepsi durup düşünmek için sebeptir.
Schema tasarımı bir kez yapılıp unutulan bir iş değildir; uygulama erişim desenleri değiştikçe yeniden değerlendirilir. MongoDB modelleme pratiklerini ve aggregation senaryolarını daha geniş bir bağlamda eğitim materyalleri üzerinden inceleyebilirsiniz.
Sonuç olarak "schemaless" kelimesi, tasarım yapmamak için bir bahane değil; tasarımı kod tarafında bilinçli yapmak için bir davettir. Anti-pattern'leri tanıyan ekipler, üretimde geri dönülmesi pahalı kararları en başta vermez.



