Takip et

MongoDB Sorgularınız Yavaş mı Çalışıyor? Performansı Nasıl Artırırsınız?

MongoDB İndeksleri: Node.js ile Sorgu Performansını Nasıl İyileştirirsiniz?

MongoDB Sorgularınız Yavaş mı Çalışıyor? Performansı Nasıl Artırırsınız?

MongoDB sorgu performansını Node.js uygulamalarınızda optimize etmek mi istiyorsunuz? İndekslerin gücünü keşfedin ve veri tabanı işlemlerinizi hızlandırarak kullanıcı deneyiminizi geliştirin. Büyük veri kümeleriyle çalışırken veya yoğun sorgu trafiği olan uygulamalar geliştirirken, veri tabanı performansını göz ardı etmek, kullanıcı deneyimini doğrudan etkileyen ciddi sorunlara yol açabilir. Özellikle Node.js gibi modern, yüksek performanslı bir çalışma zamanı ile MongoDB gibi esnek bir NoSQL veri tabanını bir araya getirdiğinizde, uygulamanızın hızını belirleyen en kritik faktörlerden biri, veri tabanı sorgularınızın ne kadar verimli çalıştığıdır. Peki, sorgularınızın yanıt süresi uzadığında, kullanıcılarınızın bekleme süreleri arttığında veya uygulamanız genel olarak yavaşladığında ne yapmalısınız? İşte bu noktada MongoDB indeksleri devreye giriyor ve veri tabanı performansınızı adeta sihirli bir dokunuşla bambaşka bir seviyeye taşıyor.

Bu makalede, MongoDB indekslerinin temel prensiplerinden başlayarak, farklı indeks türlerini, Node.js ile indeksleri nasıl oluşturacağınızı ve yöneteceğinizi adım adım keşfedeceğiz. Ayrıca, sorgu planlarını analiz etmek için explain() metodunu nasıl kullanacağınızı, gerçek dünya senaryolarında indeks optimizasyonlarını nasıl uygulayacağınızı ve ileri düzey ipuçlarını da ele alacağız. Amacımız, uygulamanızın veri erişim hızını artırarak, daha akıcı ve daha duyarlı bir kullanıcı deneyimi sunmanıza yardımcı olmaktır. İster yeni başlayan bir geliştirici olun ister deneyimli bir profesyonel, bu rehber, MongoDB indeksleme stratejilerinizi geliştirmek ve Node.js uygulamalarınızın potansiyelini tam olarak ortaya çıkarmak için size kapsamlı bir yol haritası sunacaktır. Hazırsanız, MongoDB indekslerinin derinliklerine dalalım ve sorgu performansınızı nasıl zirveye taşıyacağınızı öğrenelim.

MongoDB İndeksleri Nedir ve Neden Önemlidir?

MongoDB indeksleri, veri tabanındaki belgeler üzerinde hızlı ve verimli arama işlemleri yapılmasına olanak tanıyan özel veri yapılarıdır. Bu kavramı daha iyi anlamak için bir analoji kullanabiliriz: Büyük bir ansiklopedi düşünün. Eğer bu ansiklopedide belirli bir konuyu arıyorsanız, her sayfayı tek tek karıştırmak yerine, ansiklopedinin sonundaki indeksi kullanırsınız. İndeks, aradığınız konunun hangi sayfalarda geçtiğini size anında gösterir. MongoDB indeksleri de tam olarak bu prensiple çalışır; veri tabanınızdaki koleksiyonlarda belirli alanlar üzerinde bir tür kısayol veya harita oluşturur.

Peki, indeksler tam olarak nasıl çalışır? Çoğu MongoDB indeksi, B-tree (dengeli ağaç) veri yapısını kullanır. Bu yapı, verileri sıralı bir şekilde depolar ve bu sayede belirli bir değeri aramak, aralık sorguları yapmak veya verileri sıralamak çok daha hızlı hale gelir. İndeksler, genellikle sıkça sorgulanan, filtrelenen veya sıralanan alanlar üzerine oluşturulur. Bir indeks oluşturduğunuzda, MongoDB, o alanın değerlerini ve ilgili belgenin konumunu içeren ayrı bir veri yapısı oluşturur. Böylece, bir sorgu geldiğinde, MongoDB tüm koleksiyonu taramak (full collection scan – COLLSCAN) yerine, doğrudan indekse başvurarak ilgili belgelere çok daha hızlı ulaşabilir (index scan – IXSCAN).

İndekslerin sağladığı faydalar saymakla bitmez. En belirgin faydası, elbette, sorgu hızlandırmasıdır. Özellikle büyük koleksiyonlarda, uygun indeksler olmadan yapılan sorgular dakikalar sürebilirken, indekslerle bu süre milisaniyelere inebilir. Ayrıca, indeksler yalnızca arama işlemlerini değil, aynı zamanda sıralama (sort) işlemlerini de hızlandırır. Eğer bir sorgu hem filtreleme hem de sıralama içeriyorsa ve bu alanlar üzerinde uygun bir bileşik indeks varsa, MongoDB hem filtreleme hem de sıralama işlemini indeks üzerinden yaparak performansı maksimize eder. İndeksler ayrıca, belirli bir alanın benzersiz olmasını sağlamak gibi kısıtlamalar uygulamak için de kullanılabilir; örneğin, bir e-posta adresinin veri tabanında sadece bir kez bulunmasını garanti edebilirsiniz.

Ancak, indekslerin bazı maliyetleri de vardır. Her indeks, disk üzerinde ek yer kaplar ve veri tabanınızın toplam boyutunu artırır. Daha da önemlisi, bir belgeye her yazma (insert, update, delete) işlemi yapıldığında, ilgili indekslerin de güncellenmesi gerekir. Bu durum, yazma yoğun uygulamalarda indekslerin yazma performansını düşürmesine neden olabilir. Bu nedenle, indeksleri stratejik bir şekilde ve yalnızca gerçekten ihtiyaç duyulan alanlara uygulamak önemlidir. Kısacası, indeksler, okuma yoğun uygulamalar için bir cankurtaran halatıyken, yazma yoğun uygulamalarda dikkatli bir şekilde yönetilmesi gereken güçlü bir araçtır. Doğru indeksleme stratejileriyle, Node.js uygulamanızın MongoDB ile olan etkileşimini dramatik bir şekilde iyileştirebilirsiniz.

İndeks Türleri ve Kullanım Senaryoları: Hangi İndeks Türü Sizin İçin Uygun?

MongoDB, farklı sorgu ihtiyaçlarını karşılamak üzere çeşitli indeks türleri sunar. Her bir indeks türü, belirli senaryolar için optimize edilmiştir ve uygulamanızın performansını artırmak için doğru indeksi seçmek kritik öneme sahiptir. Bu bölümde, en yaygın indeks türlerini ve bunların hangi durumlarda kullanılması gerektiğini detaylı bir şekilde inceleyeceğiz.

Tek Alan İndeksleri: En Basit ve Etkili Çözüm

Tek alan indeksleri, adından da anlaşılacağı gibi, bir koleksiyondaki tek bir alan üzerine oluşturulan indekslerdir. Bu, MongoDB’deki en temel ve en yaygın indeks türüdür. Bir alan üzerinde filtreleme veya sıralama yaptığınızda, tek alan indeksi sorgu performansını önemli ölçüde artırabilir. Örneğin, bir kullanıcı koleksiyonunuz varsa ve kullanıcıları e-posta adresine göre sık sık arıyorsanız, email alanı üzerinde bir tek alan indeksi oluşturmak çok mantıklı olacaktır. Bu indeksler, verileri artan (1) veya azalan (-1) sırada depolayabilir. Çoğu durumda, sıralama yönü performans üzerinde büyük bir etkiye sahip değildir, ancak bazen belirli sıralama sorguları için doğru yönü seçmek faydalı olabilir. Tek alan indeksleri, basit find() sorguları, sort() işlemleri ve $exists, $type gibi operatörlerle yapılan filtrelemeler için idealdir. Uygulamanızdaki temel arama ve filtreleme ihtiyaçları için genellikle ilk tercihiniz olmalıdır.


      db.kullanicilar.createIndex({ email: 1 });
    

Bileşik İndeksler: Çoklu Alanlarda Sorgulama ve Sıralama

Bileşik indeksler, birden fazla alanı tek bir indekste birleştirir. Bu indeksler, aynı anda birden fazla alana göre filtreleme yapan veya bir alana göre filtreleyip diğerine göre sıralayan sorgular için oldukça etkilidir. Bileşik indekslerde alanların sırası kritik öneme sahiptir. MongoDB, indeksleri soldan sağa doğru kullanır, bu nedenle sorgunuzun en seçici alanını (yani en çok filtreleme yapan alanı) indeksin başına koymak genellikle en iyi performansı sağlar. Bu kurala ESR (Equality, Sort, Range) kuralı denir: Eşitlik sorguları ($eq), sıralama ($sort) ve aralık sorguları ($gt, $lt) sırasına göre alanlarınızı indekslemelisiniz. Örneğin, bir e-ticaret uygulamasında ürünleri kategoriye göre filtreleyip fiyata göre sıralıyorsanız, { kategori: 1, fiyat: 1 } şeklinde bir bileşik indeks, bu tür sorguları çok hızlı hale getirecektir. Ancak, yalnızca fiyat alanına göre bir sorgu yaparsanız, bu indeksin fiyat kısmını tek başına kullanamayacağını unutmayın; MongoDB’nin indeksi kullanabilmesi için sorgunuzun indeksin baştaki alanlarını içermesi gerekir. Bileşik indeksler, özellikle karmaşık filtreleme ve sıralama kombinasyonları içeren sorgular için vazgeçilmezdir.


      db.urunler.createIndex({ kategori: 1, fiyat: -1 }); // Kategoriye göre artan, fiyata göre azalan
    

Çok Anahtarlı (Multikey) İndeksler: Dizi Alanları İçin Optimizasyon

MongoDB, bir belgedeki dizi (array) içeren bir alan üzerinde indeks oluşturduğunuzda, otomatik olarak bir çok anahtarlı indeks oluşturur. Bu indeks türü, dizinin her bir elemanı için ayrı bir indeks girişi oluşturur. Bu sayede, bir dizinin içinde belirli bir değeri arayan sorgular çok daha hızlı çalışır. Örneğin, bir belgenin etiketler adında bir dizi alanı varsa ve bu etiketler arasında arama yapmak istiyorsanız, etiketler alanı üzerinde bir indeks oluşturmanız yeterlidir. MongoDB, bu indeksi otomatik olarak çok anahtarlı bir indeks olarak algılar ve yönetir. Bu indeksler, $in, $all gibi dizi operatörleriyle yapılan sorgular için idealdir. Çok anahtarlı indeksler, özellikle etiketler, kategoriler, yetkiler gibi birden fazla değere sahip olabilen alanları sıkça sorguladığınız senaryolarda hayat kurtarıcıdır.


      db.makaleler.createIndex({ etiketler: 1 }); // "etiketler" bir dizi olsa bile çalışır
    

TTL (Time-To-Live) İndeksler: Otomatik Veri Silme İşlemleri

TTL indeksleri, belirli bir süre sonra belgeleri otomatik olarak bir koleksiyondan silmek için kullanılır. Bu indeksler, genellikle oturum verileri, log kayıtları, önbellek verileri gibi belirli bir ömrü olan verileri yönetmek için idealdir. Bir TTL indeksi oluşturduğunuzda, bir tarih (Date) alanını ve belgelerin ne kadar süre sonra silineceğini belirten bir saniye değerini belirtirsiniz. MongoDB, arka planda çalışan bir işlemle, süresi dolan belgeleri otomatik olarak temizler. Bu, manuel temizleme işlemlerine gerek kalmadan veri tabanınızın boyutunu yönetmenize ve güncel kalmasını sağlamanıza yardımcı olur. TTL indeksleri, veri tabanınızdaki “eski” verilerin otomatik olarak temizlenmesini sağlayarak disk alanı ve performans optimizasyonu açısından büyük kolaylık sağlar.


      db.loglar.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 }); // 1 saat sonra sil
    

Text İndeksler: Metin Arama Yetenekleri

Text indeksleri, koleksiyonlardaki metin içeriği üzerinde tam metin arama yapılmasına olanak tanır. Bu indeksler, genellikle blog yazıları, ürün açıklamaları, yorumlar gibi büyük metin alanlarında anahtar kelime aramaları yapmak için kullanılır. Bir text indeksi oluşturduğunuzda, MongoDB, belirtilen alanlardaki kelimeleri indeksler ve bu kelimeler üzerinde hızlı arama yapılmasını sağlar. Text indeksleri, $text operatörü ve $search sorgu operatörü ile birlikte kullanılır. Ayrıca, arama sonuçlarını alaka düzeyine göre sıralamak için bir skor ($meta: "textScore") da döndürebilir. Tek bir koleksiyonda yalnızca bir text indeksi olabilir, ancak bu indeks birden fazla metin alanını kapsayabilir. Bu, kullanıcıların uygulamanızda güçlü ve esnek metin aramaları yapmasını sağlamak için harika bir yoldur.


      db.makaleler.createIndex({ baslik: "text", icerik: "text" });
      // Sorgu örneği:
      // db.makaleler.find({ $text: { $search: "MongoDB performans" } });
    

Geospasyal İndeksler: Konum Tabanlı Sorgular

Geospasyal indeksler, coğrafi konum verileri üzerinde sorgulama yapmak için tasarlanmıştır. Bu indeksler, belirli bir noktaya yakın yerleri bulma ($near, $geoWithin), belirli bir alan içindeki noktaları sorgulama veya iki nokta arasındaki mesafeyi hesaplama gibi konum tabanlı uygulamalar için vazgeçilmezdir. MongoDB iki ana geospasyal indeks türü sunar: 2dsphere indeksleri ve 2d indeksleri. 2dsphere indeksleri, dünya üzerindeki küresel yüzeylerdeki konumları (enlem ve boylam) destekler ve karmaşık coğrafi sorgular için daha güçlüdür. 2d indeksleri ise daha basit, düzlemsel (iki boyutlu) koordinatlar için kullanılır. Harita tabanlı uygulamalar, konum tabanlı servisler veya lojistik uygulamaları geliştiriyorsanız, geospasyal indeksler sorgu performansınızı dramatik bir şekilde iyileştirecektir.


      db.restoranlar.createIndex({ konum: "2dsphere" }); // Konum "GeoJSON" formatında olmalı
    

Her indeks türünün kendine özgü avantajları ve kullanım alanları vardır. Uygulamanızın sorgu desenlerini ve veri erişim ihtiyaçlarını dikkatlice analiz ederek, en uygun indeks kombinasyonlarını seçmek, MongoDB veri tabanınızın ve dolayısıyla Node.js uygulamanızın genel performansını maksimize etmenin anahtarıdır. Doğru indeksleme stratejisiyle, veri tabanınızdaki verilere erişim hızını artırabilir ve kullanıcılarınıza daha akıcı bir deneyim sunabilirsiniz.

Node.js ile MongoDB İndekslerini Nasıl Oluşturur ve Yönetirsiniz?

Node.js uygulamalarınızda MongoDB indekslerini oluşturmak ve yönetmek oldukça kolaydır. MongoDB’nin resmi Node.js sürücüsü veya popüler bir ODM (Object Data Modeling) kütüphanesi olan Mongoose aracılığıyla bu işlemleri gerçekleştirebilirsiniz. Her iki yaklaşım da benzer mantıkla çalışır, ancak Mongoose, schema tabanlı yapısıyla daha entegre bir deneyim sunar. İşte adım adım Node.js ile indeksleri nasıl oluşturacağınız ve yöneteceğinize dair detaylı bir rehber:

MongoDB Driver ile İndeks Oluşturma

Öncelikle, uygulamanızda MongoDB driver’ını kurmanız ve bir veri tabanı bağlantısı oluşturmanız gerekir. Ardından, createIndex() metodunu kullanarak indekslerinizi tanımlayabilirsiniz. Bu metod, belirtilen alanlar üzerinde bir indeks oluşturur. Eğer aynı isimde bir indeks zaten varsa, MongoDB mevcut indeksi yeniden oluşturmaz; bu, işlemin idempotent olduğu anlamına gelir.


      const { MongoClient } = require('mongodb');

      async function connectToDb() {
        const uri = "mongodb://localhost:27017"; // Kendi MongoDB URI'nizi buraya yazın
        const client = new MongoClient(uri);

        try {
          await client.connect();
          console.log("MongoDB'ye başarıyla bağlandı!");
          const db = client.db("uygulamaDb"); // Veri tabanı adınız
          const collection = db.collection("kullanicilar"); // Koleksiyon adınız

          // Tek alan indeksi oluşturma
          await collection.createIndex({ email: 1 });
          console.log("Email alanı için tek alan indeksi oluşturuldu.");

          // Bileşik indeks oluşturma
          await collection.createIndex({ kategori: 1, fiyat: -1 });
          console.log("Kategori ve fiyat için bileşik indeks oluşturuldu.");

          // TTL indeksi oluşturma (örneğin, log kayıtları için)
          await collection.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 });
          console.log("Loglar için TTL indeksi oluşturuldu (1 saat ömürlü).");

          // Mevcut indeksleri listeleme
          const indexes = await collection.indexes();
          console.log("Koleksiyondaki mevcut indeksler:", indexes);

          // İndeks silme (örneğin, "email_1" adındaki indeksi)
          // İndeks adını 'indexes' çıktısından alabilirsiniz, genellikle alan adı ve sıralama yönü ile oluşur.
          // await collection.dropIndex("email_1");
          // console.log("Email indeksi silindi.");

        } catch (error) {
          console.error("MongoDB işlemi sırasında bir hata oluştu:", error);
        } finally {
          await client.close();
          console.log("MongoDB bağlantısı kapatıldı.");
        }
      }

      connectToDb();
    

Yukarıdaki örnekte, createIndex() metodunu kullanarak farklı indeks türlerini nasıl oluşturabileceğinizi görebilirsiniz. expireAfterSeconds seçeneği TTL indeksleri için kullanılırken, diğer indeks türleri için ek seçenekler (örneğin, unique: true for unique indexes) de belirtebilirsiniz. collection.indexes() metodu, bir koleksiyondaki tüm indekslerin bir listesini döndürürken, collection.dropIndex() metodu belirli bir indeksi silmek için kullanılır. MongoDB’nin eski sürümlerinde kullanılan ensureIndex() metodu artık deprecated (kullanımdan kaldırılmıştır) ve yerine createIndex() kullanılmalıdır.

Mongoose ile İndeks Oluşturma

Mongoose kullanıyorsanız, indeksleri doğrudan schema tanımınız içinde belirtebilirsiniz, bu da kodunuzu daha düzenli ve okunabilir hale getirir. Mongoose, uygulamanız başladığında bu indeksleri otomatik olarak oluşturmaya çalışır. Ancak, üretim ortamlarında bu otomatik oluşturma işlemini devre dışı bırakıp indeksleri manuel olarak veya bir migrasyon scripti aracılığıyla yönetmek daha güvenli bir yaklaşım olabilir.


      const mongoose = require('mongoose');

      mongoose.connect('mongodb://localhost:27017/uygulamaDb', { useNewUrlParser: true, useUnifiedTopology: true })
        .then(() => console.log('MongoDB Mongoose ile başarıyla bağlandı!'))
        .catch(err => console.error('Mongoose bağlantı hatası:', err));

      const KullaniciSchema = new mongoose.Schema({
        ad: String,
        email: { type: String, required: true, unique: true }, // Benzersiz indeks otomatik oluşur
        createdAt: { type: Date, default: Date.now }
      });

      // Tek alan indeksi tanımlama
      KullaniciSchema.index({ ad: 1 });

      // Bileşik indeks tanımlama
      const UrunSchema = new mongoose.Schema({
        isim: String,
        kategori: String,
        fiyat: Number,
        stok: Number
      });

      UrunSchema.index({ kategori: 1, fiyat: -1 });

      // TTL indeksi tanımlama (örneğin, oturumlar için)
      const SessionSchema = new mongoose.Schema({
        sessionData: Object,
        createdAt: { type: Date, expires: '1h', default: Date.now } // 1 saat sonra sil
      });

      const Kullanici = mongoose.model('Kullanici', KullaniciSchema);
      const Urun = mongoose.model('Urun', UrunSchema);
      const Session = mongoose.model('Session', SessionSchema);

      async function createMongooseIndexes() {
        try {
          await Kullanici.createIndexes(); // Tüm tanımlı indeksleri oluşturur
          console.log("Kullanıcı indeksleri oluşturuldu.");

          await Urun.createIndexes();
          console.log("Ürün indeksleri oluşturuldu.");

          await Session.createIndexes();
          console.log("Oturum TTL indeksi oluşturuldu.");

          // İndeksleri kontrol etmek için:
          // const userIndexes = await Kullanici.listIndexes();
          // console.log("Kullanıcı koleksiyonu indeksleri:", userIndexes);

        } catch (error) {
          console.error("Mongoose indeks oluşturma hatası:", error);
        } finally {
          // mongoose.connection.close();
        }
      }

      createMongooseIndexes();
    

Mongoose’da, unique: true seçeneğini bir schema alanına eklediğinizde, Mongoose o alan için otomatik olarak benzersiz bir indeks oluşturur. TTL indeksleri için expires seçeneğini kullanabilirsiniz (örneğin, expires: '1h' veya expires: 3600). Tüm tanımlı indeksleri oluşturmak için model üzerinde createIndexes() metodunu çağırabilirsiniz. Bu metod, uygulamanızın başlangıcında veya belirli bir migrasyon scripti içinde çalıştırılabilir.

İndeksleri oluşturduktan sonra, bunların gerçekten sorgu performansınızı iyileştirip iyileştirmediğini anlamak için sorgu planlarını analiz etmeniz gerekecektir. Bu, bir sonraki bölümde ele alacağımız explain() metodu ile mümkün olacaktır. İndeks yönetimi, uygulamanızın yaşam döngüsü boyunca devam eden bir süreçtir; yeni sorgu desenleri ortaya çıktıkça veya veri boyutları değiştikçe indekslerinizi gözden geçirmeniz ve ayarlamanız gerekebilir.

Sorgu Planlarını Anlamak: explain() Metodu ile Performansı Nasıl Analiz Edersiniz?

MongoDB’deki explain() metodu, bir sorgunun nasıl yürütüldüğünü, hangi indeksleri kullandığını ve genel olarak performansını anlamak için paha biçilmez bir araçtır. Bir sorgunun yavaş çalıştığını fark ettiğinizde, ilk yapmanız gereken şeylerden biri explain() metodunu kullanarak sorgunun “sorgu planını” incelemektir. Bu, sorgunun neden yavaş olduğunu anlamanıza ve uygun indeksleme stratejileriyle nasıl iyileştirebileceğinize dair net bir yol haritası sunar.

explain() metodu, üç farklı detay seviyesinde bilgi sağlayabilir: queryPlanner, executionStats ve allPlansExecution. Her seviye, sorgunun yürütülmesi hakkında farklı bir derinlikte bilgi sunar:

  • queryPlanner: Bu mod, MongoDB’nin sorgu için seçtiği “kazanan” planı ve neden diğer planları reddettiğini gösterir. Hangi indekslerin göz önünde bulundurulduğunu ve hangisinin seçildiğini buradan görebilirsiniz. Ancak, sorgunun fiili yürütme istatistiklerini içermez.
  • executionStats: Bu mod, sorgunun fiili yürütme istatistiklerini (örneğin, taranan belge sayısı, taranan indeks anahtarı sayısı, toplam yürütme süresi) içerir. Bu, performans darboğazlarını belirlemek için en sık kullanılan moddur ve bize COLLSCAN (tüm koleksiyonu tarama) mı yoksa IXSCAN (indeks taraması) mı yapıldığını gösterir.
  • allPlansExecution: En detaylı moddur. Hem queryPlanner hem de executionStats bilgilerini içerir ve ayrıca MongoDB’nin sorgu için denediği tüm olası planların yürütme istatistiklerini de gösterir. Bu, özellikle karmaşık sorgular için çok sayıda indeks seçeneği olduğunda faydalıdır.

Node.js’te, bir sorgunun explain() çıktısını almak için collection.find().explain() metodunu kullanabilirsiniz. İşte bir örnek:


      const { MongoClient } = require('mongodb');

      async function analyzeQueryPerformance() {
        const uri = "mongodb://localhost:27017";
        const client = new MongoClient(uri);

        try {
          await client.connect();
          const db = client.db("uygulamaDb");
          const collection = db.collection("urunler");

          // Örnek veri ekleme (eğer koleksiyon boşsa)
          // await collection.insertMany([
          //   { isim: "Laptop", kategori: "Elektronik", fiyat: 1200, stok: 50 },
          //   { isim: "Klavye", kategori: "Elektronik", fiyat: 75, stok: 200 },
          //   { isim: "Fare", kategori: "Elektronik", fiyat: 30, stok: 300 },
          //   { isim: "Defter", kategori: "Kırtasiye", fiyat: 10, stok: 500 },
          //   { isim: "Kalem", kategori: "Kırtasiye", fiyat: 5, stok: 1000 }
          // ]);

          // İndeks olmadan yavaş bir sorgu
          console.log("--- İndeks Olmadan Sorgu Analizi ---");
          const explainResultNoIndex = await collection.find({ kategori: "Elektronik", fiyat: { $gt: 50 } }).explain("executionStats");
          console.log(explainResultNoIndex.executionStats);

          // Çıktıda 'COLLSCAN' (Collection Scan) ve 'totalDocsExamined' ile 'totalKeysExamined' değerlerinin yüksek olması beklenir.

          // Şimdi bir indeks oluşturalım
          await collection.createIndex({ kategori: 1, fiyat: 1 });
          console.log("\nKategori ve fiyat için bileşik indeks oluşturuldu.");

          // İndeks ile hızlı bir sorgu
          console.log("--- İndeks İle Sorgu Analizi ---");
          const explainResultWithIndex = await collection.find({ kategori: "Elektronik", fiyat: { $gt: 50 } }).explain("executionStats");
          console.log(explainResultWithIndex.executionStats);

          // Çıktıda 'IXSCAN' (Index Scan) ve 'totalKeysExamined' değerinin 'totalDocsExamined' değerine göre çok daha düşük olması beklenir.
          // 'winningPlan.inputStage.stage' alanında 'IXSCAN' görmelisiniz.

        } catch (error) {
          console.error("Sorgu analizi sırasında bir hata oluştu:", error);
        } finally {
          await client.close();
        }
      }

      analyzeQueryPerformance();
    

explain() çıktısını incelerken dikkat etmeniz gereken bazı temel metrikler şunlardır:

  • winningPlan.inputStage.stage: Bu alan, MongoDB’nin sorgu için kullandığı ana işlemi gösterir. Eğer burada COLLSCAN görüyorsanız, MongoDB tüm koleksiyonu tarıyor demektir ve bu genellikle indeks eksikliğinden kaynaklanan bir performans sorunudur. IXSCAN görmek ise, sorgunun bir indeksi verimli bir şekilde kullandığı anlamına gelir.
  • totalDocsExamined: Sorgu tarafından incelenen toplam belge sayısı. Bu değer ne kadar düşükse, sorgu o kadar verimlidir.
  • totalKeysExamined: Sorgu tarafından incelenen toplam indeks anahtarı sayısı. Eğer totalDocsExamined değerinden çok daha düşükse, bu iyi bir indekse sahip olduğunuzu gösterir.
  • executionTimeMillis: Sorgunun yürütülmesi için geçen toplam süre (milisaniye cinsinden).
  • rejectedPlans: MongoDB’nin denediği ancak kazanan plan olarak seçmediği diğer sorgu planları. Bu, potansiyel olarak faydalı olabilecek ancak mevcut sorgu için optimize edilmemiş indeksleri gösterebilir.

Vaka Analizi: Bir Node.js uygulamasında, kullanıcıların siparişlerini tarih aralığına göre filtreleyen bir raporlama sayfasının yavaş çalıştığını varsayalım. explain("executionStats") çıktısına baktığınızda, stage: "COLLSCAN" ve çok yüksek totalDocsExamined değerleri görüyorsunuz. Bu, veri tabanının her sipariş belgesini tek tek taradığını gösterir. Çözüm olarak, siparisTarihi: 1 üzerinde bir indeks oluşturursunuz. İndeks oluşturulduktan sonra aynı sorguyu tekrar explain() ile analiz ettiğinizde, stage: "IXSCAN" ve çok daha düşük totalDocsExamined ile totalKeysExamined değerleri görürsünüz. Bu, sorgunuzun artık indeksi kullanarak çok daha hızlı çalıştığı anlamına gelir. explain() metodu, indeksleme stratejilerinizi geliştirirken ve performans sorunlarını giderirken en güçlü müttefiklerinizden biridir.

Gerçek Dünya Senaryoları: Node.js Uygulamalarında İndeks Optimizasyonu

Teorik bilgileri gerçek dünya örnekleriyle pekiştirmek, indekslerin gücünü ve Node.js uygulamalarınızda nasıl fark yaratabileceğini daha iyi anlamanıza yardımcı olacaktır. İşte farklı uygulama türleri için indeks optimizasyon senaryoları:

E-ticaret Sitesi İçin Ürün Araması: Hızlı Kategori ve Fiyat Filtrelemesi

Bir e-ticaret sitesinde, kullanıcılar genellikle ürünleri kategoriye göre filtreler ve ardından fiyata göre artan veya azalan sırada sıralarlar. Bu, çok yaygın bir sorgu desenidir ve performans açısından kritik öneme sahiptir. Eğer yüz binlerce veya milyonlarca ürününüz varsa ve bu sorgular indekslenmemişse, her sorgu tüm ürün koleksiyonunu tarayarak saniyeler sürebilir.

Senaryo: Kullanıcılar “Elektronik” kategorisindeki ürünleri görmek istiyor ve sonuçları fiyata göre en düşükten en yükseğe sıralıyor.

Çözüm: Bu senaryo için en uygun indeks, kategori ve fiyat alanlarını içeren bir bileşik indekstir. ESR kuralına göre, eşitlik sorgusu (kategori) önce, sıralama (fiyat) sonra gelmelidir.


      // Mongoose Schema örneği
      const mongoose = require('mongoose');
      const UrunSchema = new mongoose.Schema({
        isim: String,
        kategori: String,
        fiyat: Number,
        stok: Number,
        marka: String
      });

      // İndeksi tanımla
      UrunSchema.index({ kategori: 1, fiyat: 1 }); // Kategoriye göre artan, fiyata göre artan

      const Urun = mongoose.model('Urun', UrunSchema);

      // Node.js sorgu örneği
      async function getUrunlerByKategoriAndFiyat(kategoriAdi, minFiyat = 0) {
        try {
          const urunler = await Urun.find({
            kategori: kategoriAdi,
            fiyat: { $gt: minFiyat }
          }).sort({ fiyat: 1 }).limit(10); // Fiyata göre sırala
          console.log(Kategori: ${kategoriAdi}, Minimum Fiyat: ${minFiyat} olan ürünler:, urunler);
          return urunler;
        } catch (error) {
          console.error("Ürün sorgulama hatası:", error);
        }
      }

      // getUrunlerByKategoriAndFiyat("Elektronik", 50);
    

Bu bileşik indeks sayesinde, MongoDB önce kategori alanını kullanarak hızlıca “Elektronik” kategorisindeki ürünleri bulacak, ardından bu subset içindeki fiyat alanını kullanarak sıralama işlemini gerçekleştirecektir. Bu, tam koleksiyon taraması yapmaktan çok daha hızlıdır ve kullanıcıya anında sonuçlar sunar.

Sosyal Medya Akışı: Kullanıcı Gönderilerini Zaman Bazlı Getirme

Bir sosyal medya uygulamasında, kullanıcılar genellikle kendi profil sayfalarında veya ana sayfalarında en son gönderilerini kronolojik sıraya göre görmek isterler. Bu, kullanıcı kimliğine göre filtreleme ve gönderi tarihine göre azalan sırada sıralama gerektiren bir işlemdir.

Senaryo: Belirli bir kullanıcının en son 20 gönderisini hızlıca getirme.

Çözüm: Bu durumda, kullaniciId ve createdAt alanlarını içeren bir bileşik indeks idealdir.


      // Mongoose Schema örneği
      const mongoose = require('mongoose');
      const GonderiSchema = new mongoose.Schema({
        kullaniciId: mongoose.Schema.Types.ObjectId,
        icerik: String,
        createdAt: { type: Date, default: Date.now }
      });

      // İndeksi tanımla
      GonderiSchema.index({ kullaniciId: 1, createdAt: -1 }); // Kullanıcı ID'ye göre artan, tarihe göre azalan

      const Gonderi = mongoose.model('Gonderi', GonderiSchema);

      // Node.js sorgu örneği
      async function getUserPosts(userId) {
        try {
          const posts = await Gonderi.find({ kullaniciId: userId })
                                    .sort({ createdAt: -1 })
                                    .limit(20);
          console.log(Kullanıcı ${userId} için son gönderiler:, posts);
          return posts;
        } catch (error) {
          console.error("Gönderi sorgulama hatası:", error);
        }
      }

      // getUserPosts(new mongoose.Types.ObjectId("60c72b2f9b1e8b001c8e4d1a")); // Örnek kullanıcı ID
    

Bu indeks, MongoDB’nin önce kullaniciId alanını kullanarak hızlıca ilgili kullanıcının gönderilerini bulmasını, ardından createdAt alanını kullanarak bu gönderileri en yenisinden en eskisine doğru sıralamasını sağlar. Bu, özellikle milyonlarca gönderi içeren koleksiyonlarda sorgu performansını büyük ölçüde artırır.

Log Yönetim Sistemi: Eski Logları Otomatik Temizleme

Uygulamalar genellikle sistem olaylarını, hataları veya kullanıcı etkileşimlerini kaydetmek için loglar tutar. Bu log koleksiyonları zamanla çok büyüyebilir ve disk alanını tüketebilir. Belirli bir süreden eski logların otomatik olarak silinmesi, veri tabanının boyutunu yönetmek ve performansını korumak için önemlidir.

Senaryo: Uygulama loglarını 7 gün sonra otomatik olarak veri tabanından silme.

Çözüm: createdAt (oluşturulma tarihi) alanı üzerinde bir TTL (Time-To-Live) indeksi kullanmak bu iş için mükemmeldir.


      // Mongoose Schema örneği
      const mongoose = require('mongoose');
      const LogSchema = new mongoose.Schema({
        mesaj: String,
        seviye: String, // info, warn, error
        createdAt: { type: Date, default: Date.now }
      });

      // TTL indeksi tanımla: 7 gün = 7 * 24 * 60 * 60 = 604800 saniye
      LogSchema.index({ createdAt: 1 }, { expireAfterSeconds: 604800 });

      const Log = mongoose.model('Log', LogSchema);

      // Log kaydı ekleme örneği
      async function addLog(message, level) {
        try {
          const newLog = new Log({ mesaj: message, seviye: level });
          await newLog.save();
          console.log("Yeni log kaydedildi:", newLog);
        } catch (error) {
          console.error("Log kaydetme hatası:", error);
        }
      }

      // addLog("Kullanıcı giriş yaptı", "info");
    

Bu TTL indeksi sayesinde, MongoDB arka planda otomatik olarak createdAt alanı 7 günden daha eski olan log belgelerini siler. Bu, manuel temizleme scriptleri yazma ve çalıştırma ihtiyacını ortadan kaldırır, veri tabanının sürekli optimize edilmesini sağlar ve disk alanı kullanımını kontrol altında tutar. Bu gerçek dünya senaryoları, doğru indeksleme stratejilerinin Node.js uygulamalarınızın performansını nasıl kökten değiştirebileceğini göstermektedir. Her zaman uygulamanızın sorgu desenlerini analiz edin ve bu desenlere en uygun indeksleri oluşturmaya odaklanın.

İleri Düzey İndeks İpuçları ve En İyi Uygulamalar

MongoDB indeksleme, temel kullanımların ötesine geçen birçok ileri düzey özelliğe sahiptir. Bu ipuçları, daha karmaşık senaryolarda performans optimizasyonunu daha da derinleştirmenize yardımcı olacaktır. Ayrıca, genel olarak indeksleme stratejilerinizi geliştirmeniz için en iyi uygulamaları da ele alacağız.

Kısmi İndeksler (Partial Indexes): Daha Az Maliyetle Daha Fazla Performans

Kısmi indeksler, yalnızca belirli bir filtre koşulunu karşılayan belgeler üzerinde indeks oluşturmanıza olanak tanır. Bu, indeksin boyutunu önemli ölçüde azaltabilir ve yazma performans maliyetini düşürebilir, çünkü indeks yalnızca ilgili belgeler için güncellenir. Örneğin, bir kullanıcı koleksiyonunuz varsa ve yalnızca “aktif” durumdaki kullanıcılar üzerinde sıkça sorgu yapıyorsanız, tüm kullanıcılar yerine sadece aktif kullanıcılar için bir indeks oluşturabilirsiniz.


      db.kullanicilar.createIndex(
        { email: 1 },
        { partialFilterExpression: { status: "active" } }
      );
    

Bu indeks, yalnızca status alanı “active” olan belgeler için email alanı üzerinde bir indeks oluşturur. Bu, disk alanından tasarruf etmenizi ve indeksin güncellenmesi gereken belge sayısını azaltmanızı sağlar.

Benzersiz İndeksler (Unique Indexes): Veri Bütünlüğünü Sağlama

Benzersiz indeksler, indekslenen alanın veya alanların her belgede benzersiz olmasını garanti eder. Bu, veri bütünlüğünü sağlamak için kritik öneme sahiptir. Örneğin, bir kullanıcının e-posta adresinin veri tabanında yalnızca bir kez bulunmasını sağlamak için email alanı üzerinde benzersiz bir indeks oluşturabilirsiniz. Eğer benzersizlik kuralını ihlal eden bir belge eklemeye çalışırsanız, MongoDB bir hata döndürür.


      db.kullanicilar.createIndex(
        { email: 1 },
        { unique: true }
      );
    

Bileşik indeksler üzerinde de benzersizlik kısıtlaması uygulayabilirsiniz. Bu durumda, tüm bileşik indeksin değeri benzersiz olmalıdır.

İnce İndeksleme (Covered Queries): Performansın Zirvesi

İnce indeksleme, bir sorgunun yalnızca indeksi kullanarak tüm gerekli bilgileri alabileceği ve orijinal belgelere erişmek zorunda kalmadığı durumlarda ortaya çıkar. Bu, sorgu performansının mümkün olan en yüksek seviyesidir, çünkü MongoDB’nin diskten belge okumasına gerek kalmaz. Bir sorgunun ince indeksli olabilmesi için şu koşulları sağlaması gerekir:

  1. Sorgunun tüm filtreleme koşulları indeksin bir parçası olmalıdır.
  2. Sorgunun döndürdüğü tüm alanlar (projeksiyon) indeksin bir parçası olmalıdır.
  3. Sorguda hiçbir alan indeksin bir parçası olmayan bir diziyi içermemelidir.

      // İndeks: { kategori: 1, fiyat: 1 }
      // İnce indeksli sorgu örneği:
      db.urunler.find(
        { kategori: "Elektronik", fiyat: { $gt: 100 } },
        { kategori: 1, fiyat: 1, _id: 0 } // _id alanı her zaman dahil olduğu için hariç tutulmalı
      );
    

Bu sorgu, sadece kategori ve fiyat alanlarını döndürdüğü ve bu alanlar indekste yer aldığı için ince indeksli olacaktır.

Arka Plan İndeks Oluşturma (Background Index Creation): Canlı Sistemlerde Güvenli İndeksleme

Büyük koleksiyonlar üzerinde indeks oluşturmak, veri tabanını geçici olarak bloklayabilir ve canlı uygulamanızın yanıt sürelerini etkileyebilir. MongoDB 4.2’den önceki sürümlerde, indeksleri arka planda oluşturmak için { background: true } seçeneğini kullanmak yaygın bir uygulamaydı. Bu, indeks oluşturma işleminin veri tabanı işlemlerini bloklamadan paralel olarak çalışmasını sağlar. Ancak, MongoDB 4.2 ve sonraki sürümlerde, indeks oluşturma varsayılan olarak arka planda çalışır, bu nedenle bu seçeneği belirtmenize gerek kalmaz.


      // MongoDB 4.2+ sürümlerinde varsayılan olarak arka planda çalışır
      db.kullanicilar.createIndex({ ad: 1 });
      // Eski sürümlerde: db.kullanicilar.createIndex({ ad: 1 }, { background: true });
    

İndeks Bakımı ve İzleme

İndeksleme stratejiniz statik olmamalıdır. Uygulamanız geliştikçe, veri desenleri değiştikçe veya yeni sorgular eklendikçe indekslerinizi gözden geçirmeniz gerekir. Kullanılmayan veya nadiren kullanılan indeksleri belirlemek ve silmek, disk alanından tasarruf etmenizi ve yazma performansını artırmanızı sağlar. MongoDB Atlas gibi bulut servisleri veya db.collection.stats(), db.collection.getIndexes() gibi komutlar ile indeks kullanımını ve istatistiklerini izleyebilirsiniz.

Shardlama ve İndeksler

Büyük ölçekli dağıtık sistemlerde (sharded clusters), indeksleme stratejileri daha karmaşık hale gelir. Shard key (parçalama anahtarı) seçimi, indeks performansını doğrudan etkiler. Shard key, genellikle sıkça sorgulanan veya filtrelenen bir alan olmalıdır ve iyi bir dağılım sağlamalıdır. İndeksler, shard key üzerinde veya shard key’i içeren bileşik indeksler olarak tanımlanmalıdır.

Mobil Uyumluluk İçin HTML Yapısı

Makalenin temel konusu indeksler olsa da, modern web uygulamaları geliştirirken mobil uyumluluk da göz ardı edilemez. Node.js ile oluşturduğunuz API’ler ne kadar hızlı olursa olsun, kullanıcı arayüzünüzün farklı ekran boyutlarına uyum sağlaması önemlidir. HTML yapınızı oluştururken semantik etiketler kullanmak ve esnek bir düzen oluşturmak (örneğin, div‘ler, section‘lar kullanarak) responsive tasarım için temel oluşturur. Bu HTML yapısı, harici bir CSS dosyası içinde tanımlayacağınız medya sorguları (@media kuralları) ile farklı ekran boyutlarına (telefon, tablet, masaüstü) göre otomatik olarak ayarlanabilir. Örneğin, bir ürün listesi için kullandığınız <div class="urun-listesi"> ve içindeki <div class="urun-karti"> elementleri, küçük ekranlarda tek sütun, büyük ekranlarda ise çoklu sütun olarak gösterilmek üzere CSS medya sorguları ile hedeflenebilir. Bu sayede, uygulamanızın performansı kadar, kullanıcı deneyimi de mobil cihazlarda optimize edilmiş olur.


      <div class="container">
        <div class="header">Başlık</div>
        <div class="main-content">
          <div class="sidebar">Yan Menü</div>
          <div class="article-list">
            <div class="article-card">Makale 1</div>
            <div class="article-card">Makale 2</div>
          </div>
        </div>
        <div class="footer">Alt Bilgi</div>
      </div>
    

Yukarıdaki gibi bir HTML yapısı, CSS medya sorguları ile kolayca mobil uyumlu hale getirilebilir. Örneğin, küçük ekranlarda .sidebar gizlenebilir ve .article-card‘lar tam genişlikte gösterilebilirken, büyük ekranlarda yan menü görünür hale getirilebilir ve makale kartları yan yana dizilebilir. Bu, uygulamanızın hem performans hem de kullanılabilirlik açısından eksiksiz olmasını sağlar.

Sonuç: MongoDB İndeksleri ile Uygulamanızı Bir Üst Seviyeye Taşıyın

Bu makale boyunca, MongoDB indekslerinin Node.js uygulamalarınızın sorgu performansını nasıl kökten değiştirebileceğini detaylı bir şekilde inceledik. İndekslerin sadece bir performans aracı olmaktan öte, veri bütünlüğünü sağlamak ve belirli veri yönetimi görevlerini otomatikleştirmek için de kullanılabileceğini gördük. Tek alan indekslerinden bileşik, TTL, text ve geospasyal indekslere kadar çeşitli türleri keşfettik, her birinin kendine özgü kullanım senaryolarını ve avantajlarını ele aldık. Node.js’in resmi driver’ı ve Mongoose gibi popüler ODM’ler aracılığıyla indeksleri nasıl oluşturacağınızı ve yöneteceğinizi adım adım öğrendik.

En önemlisi, explain() metodunun gücünü keşfettik. Bu araç sayesinde, sorgularınızın arka planda nasıl çalıştığını analiz edebilir, potansiyel performans darboğazlarını belirleyebilir ve indeksleme stratejilerinizi bilinçli kararlarla optimize edebilirsiniz. Gerçek dünya senaryoları, e-ticaret aramalarından sosyal medya akışlarına ve log yönetimine kadar farklı alanlarda indekslerin nasıl somut faydalar sağladığını gösterdi. Ayrıca, kısmi indeksler, ince indeksleme ve indeks bakımı gibi ileri düzey ipuçlarıyla, uygulamanızın performansını daha da ileriye taşıma yollarını ele aldık.

Unutmayın, performans optimizasyonu sadece kod yazmaktan ibaret değildir; veri tabanı seviyesindeki stratejiler de en az kod kalitesi kadar kritik öneme sahiptir. Doğru indeksleme stratejileriyle, Node.js uygulamanızın MongoDB ile olan etkileşimini hızlandırabilir, kullanıcılarınıza daha akıcı, daha duyarlı ve genel olarak daha iyi bir deneyim sunabilirsiniz. Şimdi sıra sizde! Kendi Node.js uygulamalarınızda bu bilgileri uygulamaya başlayın, sorgularınızı explain() ile analiz edin ve indekslerin gücünü keşfederek uygulamanızı bir üst seviyeye taşıyın. Performansın zirvesine ulaşmak için doğru indeksleme anahtardır.

Sıkça Sorulan Sorular: İndeksler Hakkında Merak Ettikleriniz

1. Her alana indeks eklemeli miyim?
Hayır, kesinlikle eklememelisiniz. İndeksler disk alanı kaplar ve her yazma (insert, update, delete) işleminde güncellenmeleri gerektiği için yazma performansını düşürürler. Yalnızca sıkça sorgulanan, filtrelenen, sıralanan veya benzersizlik kısıtlaması gerektiren alanlara indeks eklemelisiniz. Fazla indeks, faydadan çok zarar getirebilir.
2. İndeksler sorgu performansını her zaman artırır mı?
Çoğu durumda evet, ancak her zaman değil. Çok küçük veri kümelerinde indeks kullanmak, indeksin kendisini okuma maliyeti nedeniyle bazen daha yavaş olabilir. Ayrıca, sorgunuz indeksi etkin bir şekilde kullanamıyorsa (örneğin, indeksin başlangıç alanlarını içermiyorsa veya çok karmaşık bir sorguysa), performans artışı gözlenmeyebilir. Bu nedenle, bir indeksi oluşturduktan sonra explain() metodu ile sorgu planını kontrol etmek esastır.
3. Bileşik indekslerde alanların sırası önemli mi?
Kesinlikle evet, alanların sırası kritik öneme sahiptir. MongoDB, bileşik indeksleri soldan sağa doğru kullanır. En iyi performans için ESR (Equality, Sort, Range) kuralını takip etmelisiniz: Eşitlik koşuluyla filtrelenen alanları indeksin en başına, ardından sıralama için kullanılan alanları ve son olarak aralık sorguları için kullanılan alanları yerleştirmelisiniz. Sorgunuz, indeksin baştaki alanlarını içermiyorsa, indeksin tamamını veya bir kısmını kullanamayabilir.
4. Üretim ortamında indeks oluşturmak güvenli midir?
MongoDB 4.2 ve sonrası sürümlerde indeks oluşturma varsayılan olarak arka planda çalışır ve çoğu durumda veri tabanı işlemlerini bloklamaz. Bu, indeks oluşturma işleminin canlı sistemlerde güvenli bir şekilde yapılmasını sağlar. Ancak, çok büyük koleksiyonlarda veya eski MongoDB sürümlerinde indeks oluşturma işlemi hala kaynak yoğun olabilir ve dikkatli bir şekilde planlanmalıdır. Her zaman öncelikle test ortamlarında denemeniz ve bakım pencerelerinde yapmanız önerilir.
5. İndeksler ne kadar disk alanı kaplar?
Bir indeksin kapladığı disk alanı, indekslenen alanın veri türüne, indeksin benzersiz olup olmamasına, indekslenen belge sayısına ve indeksin türüne (örneğin, text indeksler daha büyük olabilir) bağlıdır. Genellikle, indeksler ilgili koleksiyonun boyutunun bir kısmını kaplar, ancak çok sayıda indeks veya çok büyük alanların indekslenmesi bu oranı artırabilir. db.collection.stats() komutunu kullanarak bir koleksiyonun ve indekslerinin disk kullanımını kontrol edebilirsiniz.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.