Last chance! 50% off DataCamp Premium
Sale ends in
Her veritabanında olduğu gibi, MongoDB’de de dizinler geliştirme sürecinin kritik bir parçasıdır. Dizinler olmadan veritabanınız büyüdükçe performans düşmeye devam eder. Doğru dizinlerle ise veriniz artsa bile erişim performansı en iyi seviyede kalır.
Bu yazıda, MongoDB içinde mevcut çeşitli dizin türlerini, en iyi deneyim için bazı ipuçlarını ve oluşturduğunuz dizinlerden gerçekten yararlandığınızdan emin olmanız için yönergeleri inceleyeceğiz. MongoDB’yi hâlâ öğreniyorsanız, Introduction to MongoDB kursuna göz atmanızı öneririm.
Dizinlerden söz ettiğimizde performanstan söz ediyoruz. Dizinler, bir sorguya uyup uymadığını görmek için koleksiyondaki her belgeye bakmak ile sorgumuza uyan daha spesifik bir belge grubuna bakmak arasındaki farktır. Koleksiyonumuz küçükse ve taranacak çok belge yoksa performans her iki durumda da iyi olabilir. Ancak bir koleksiyonda 100.000 belge varsa ve yalnızca 100’ü sorgumuza uyuyorsa, bu 100’e dayalı bir dizin yoksa 100.000 belgenin tamamını gözden geçirmek zaman alacaktır.
MongoDB’de çok sayıda dizin türü vardır:
_id alanı dizini tek alanlı bir dizin olarak düşünülebilir.Çeşitli dizin türleri hakkında daha fazla bilgi için MongoDB dokümantasyonuna bakın.
Çoğu zaman tek alanlı, bileşik veya çok anahtarlı dizinler kullanırsınız; ancak nihayetinde bu, uygulamanın, sorguların ve verinin türüne bağlıdır.
Dizinler, belgeleri getiren her türlü veritabanı etkileşiminde önemlidir. Bu, find veya findOne işlemleriyle belge getirmeyle sınırlı değildir. Belgeleri güncellerken ve silerken de veritabanının güncelleme veya silme işlemi öncesinde belgeleri bulmak için kullanacağı bir eşleştirme ölçütü kullanırsınız.
Bir dizinden yararlanabilecek tek alma operatörleri find ve findOne değildir. Toplama hattınızın ilk aşamasında $match operatörünü kullandığınızda, bir dizin işleri dramatik biçimde hızlandırır.
Rastgele dizinler oluşturmak, MongoDB’de hiç dizin kullanmamak kadar verimsiz olabilir. Bunun yerine, daha verimli bir uygulama oluşturmanıza yardımcı olacak birkaç husus vardır.
Bileşik bir dizin oluştururken kural, sorgunuzdaki her alanı nasıl kullanacağınızı belirlemek ve ESR en iyi uygulamasını izlemesini sağlamaktır.
ESR ne anlama gelir? Parçalara ayıralım:
$lt veya $gt operatörünü kullanmak, belirli bir eşleşme yerine bir aralıktaki belgelere eşleşir.Tüm bunların ne anlama geldiğini daha iyi görmek için şu sorguya bakın:
db.employee.find(
{
"department": "Developer Relations",
"salary": {
"$lt": 80000
}
}
).sort(
{
"name": 1
}
);
Yukarıdaki sorgu bölümde eşitlik eşleşmesi, maaşta aralık eşleşmesi yapar ve sonuçları ada göre sıralar.
ESR kurallarını izlediğimizde dizin şöyle görünür:
db.employee.createIndex({
"department": 1,
"name": 1,
"salary": 1
});
Bellek içi sıralamaları önlemek ve performanslı bir sorgu yürütümü için arama alanını daraltmak adına ESR kurallarını takip etmek isteriz.
Genel olarak dizinleme, sorgu çalıştırılırken taranacak daha küçük bir belge alt kümesi oluşturur ve bunun sonucu olarak performansı artırır. Ancak uygulama performansınızı bir üst seviyeye çıkarmak istiyorsanız, kapsanan sorguları araştırmalısınız. Kapsanan bir sorguda, sonuçların tamamını doğrudan dizinden alırsınız; koleksiyonunuzdaki hiçbir belgeyi taramanız gerekmez.
Burada, uygulamanızda kapsanan sorguları mümkün kılabilecek ya da kılmayabilecek birkaç koşul vardır:
Peki tüm bunlar ne anlama geliyor?
Örneğin, aşağıdaki dizine bakalım:
db.department.createIndex({
"country": 1,
"salary": 1
});
Yukarıdaki örnekte belgelerimizin country ve salary alanlarına göre dizinlenmesini istiyoruz. Sonra şu sorguyu çalıştırabiliriz:
db.department.find(
{
"country": "US"
},
{
"country": 1,
"salary": 1
}
);
Projeksiyon içeren bu sorgu dizinimizi kullanacaktır, ancak kapsanan bir sorgu olmayacaktır. MongoDB’de _id alanı varsayılan olarak döndürülür ve bu örnekte _id alanı dizinimize eklenmemiştir. Dolayısıyla ya dizini ya da sorguyu değiştirebiliriz. Sorguyu değiştirme örneğinde şunu yapabiliriz:
db.department.find(
{
"country": "US"
},
{
"country": 1,
"salary": 1,
"_id": 0
}
);
Unutmayın, kapsanan bir sorgu kullanmak istiyorsanız, dizin geçerli olmalı ve talep edilen alanlar dizine dahil olmalıdır. Aksi hâlde yalnızca dizince yönetilen belgeleri bulursunuz; belgenin kendisi dizin içinde değildir.
Kapsanan bir sorgu kullanılıp kullanılmadığını, bu makalenin ilerleyen kısmında bahsedilen explain operatöründeki executionStats argümanından yararlanarak doğrulayabilirsiniz. totalDocsExamined sonucundaki değer bunu belirler. Değer sıfırsa kapsanan bir sorgu kullanıyorsunuz demektir.
Dizinler, sunucu kaynakları bağlamında ücretsiz değildir. Her dizin sunucu tarafından korunmalı ve bu bakım CPU, RAM ve disk kullanır. Daha fazla dizin oluşturdukça daha fazla ek yük yaratırsınız; bu da kaynakları yetersiz sağlanmış bir sunucu senaryosunda daha yüksek maliyetlere veya daha düşük performansa yol açabilir. Bu performans düşüşü yalnızca okumaları değil, MongoDB daha fazla kaynak tükettiği için yazma ve silmeleri de etkileyebilir.
Yalnızca yüksek frekansta çalıştırılan sorgular için dizinler oluşturmak iyi bir fikirdir. Ayda bir kez çalıştırılan o sorgunun gerçekten bir dizine ihtiyacı var mı? Muhtemelen hayır. Her 10 saniyede bir çalıştırılan o sorgunun bir dizine ihtiyacı var mı? Kesinlikle!
Birkaç dizinleme en iyi uygulamasını MongoDB Blog’da öğrenin.
MongoDB içinde bir dizin oluşturmuş olmanız, çalıştırdığınız sorgunun onu gerçekten kullandığı anlamına gelmez. MongoDB’de, belirli bir sorgu için hangi dizinin kullanıldığını analiz edebiliriz.
Örneğin, şu dizine bakalım:
db.people.createIndex({
"name": 1,
"is_active": 1
});
Yukarıdaki örnekte name ve is_active alanlarını dizinliyoruz. Şimdi şu sorguyu çalıştırmak istiyoruz:
db.people.find({
"is_active": true
});
Bu sorgu, geçerli bir dizin olsun ya da olmasın çalışacaktır ve veri kümesi küçükse her hâlükârda hızlı çalışır. Ancak dizini kullanıp kullanmadığını görmek istersek sorguya küçük bir ek yapabiliriz:
db.people.find({
"is_active": true
}).explain();
Bu kez sorgunun yürütme planını almak için explain metodunu kullanıyoruz. Yürütme planında şunu görebiliriz:
winningPlan: {
isCached: false,
stage: 'COLLSCAN',
filter: { is_active: { '$eq': true } },
direction: 'forward'
}
Bu sorgu için MongoDB "COLLSCAN" kullandı; yani alanlarımızdan birini içerse de dizinimizi kullanmadı. Sorguyu şöyle değiştirirsek:
db.people.find({
"name": "Nic Raboy",
"is_active": true
}).explain();
explain sonucumuz değişti:
winningPlan: {
isCached: false,
stage: 'FETCH',
inputStage: {
stage: 'IXSCAN',
keyPattern: { name: 1, is_active: 1 },
indexName: 'name_1_is_active_1',
isMultiKey: false,
multiKeyPaths: { name: [], is_active: [] },
isUnique: false,
isSparse: false,
isPartial: false,
indexVersion: 2,
direction: 'forward',
indexBounds: {
name: [ '["Nic Raboy", "Nic Raboy"]' ],
is_active: [ '[true, true]' ]
}
}
},
Bu kez yürütme planı "IXSCAN" kullandığımızı ve kullanılan dizinin adını belirtti; bu örnekte name_1_is_active_1. Dizin adını oluştururken otomatik olarak belirlenmişti.
update işlemi için süreç benzerdir; tek fark explain fonksiyonunun konumudur.
update işlemi şu şekilde görünebilir:
db.people.explain().update(
{
“name”: “Nic Raboy”,
“Is_active”: true
},
{
“$set”: { “is_active”: false }
}
);
Yukarıdaki örnekte explain’in update fonksiyonundan önce geldiğine dikkat edin.
Güncelleme işleminizde beklenen dizini kullanıyorsanız, "IXSCAN" değeriyle birlikte dizin adını görürsünüz. Güncelleme işlemleri ve onlarla dizin kullanımı hakkında daha fazla bilgi edinin.
Sorgunuzun yürütme planı ayrıntılarını bulmanın alternatif bir yolu da veritabanında runCommand kullanmaktır. Görünüm olarak o kadar zarif olmasa da oldukça güçlüdür ve şöyle görünür:
db.runCommand({
"explain": {
"update": "people",
"updates": [
{
"q": {
"name": "Nic Raboy",
"is_active": true
},
"u": {
"$set": { "is_active": false }
}
}
]
},
"verbosity": "allPlansExecution"
});
Yukarıdaki işlem, explain fonksiyonlu güncelleme işlemiyle aynı şekilde çalışır.
Dizin oluşturmada kendinizi yeterli hissetmiyorsanız veya sorgularınızın beklenenden yavaş çalıştığını fark ediyorsanız, yürütme ayrıntılarını kontrol etmeyi düşünün.
MongoDB’de dizinleme ile ilgili bazı en iyi uygulamaları gördünüz. Her olası dizinleme senaryosunu ele almadık; ancak bunu, kullanıcılarınızın verilerinizle çalışırken mümkün olan en iyi deneyimi almasını sağlamaya yönelik bir başlangıç noktası olarak kullanabilirsiniz.
Birkaç noktayı yineleyelim:
explain operatöründen yararlanın.Yukarıdaki maddeler, uygulama performansınızı artıracak dizinleme en iyi uygulamalarının kapsamlı bir listesi değildir. Kardinalite miktarları gibi başka etkenler de vardır.
Dizinleme konusunda daha fazla yardım için MongoDB dokümantasyonuna göz atın. MongoDB Atlas’ta ücretli bir katman kullanıyorsanız, dizin ve sorgu önerileri için yerleşik performans danışmanı araçlarını kullanmayı düşünün.
Duruma bağlıdır. Size uygun dengeyi bulmanız gerekir; ancak ara sıra yerine sıkça çalıştırılan sorgular için dizinlemeyi düşünün.
Oluşturduğunuz dizinleri sorgularınızın gerçekten kullandığından emin misiniz? Sorun gidermek için explain operatöründen veya MongoDB Atlas’taki danışman araçlarından yararlanın.
MongoDB bazen bir dizini sıra dışı da kullanabilir; ancak en etkilisi, dizin anahtar sırasının önce eşitlik filtreleri, sonra sıralamalar ve son olarak aralık olacak şekilde sorgunun sırasıyla eşleşmesidir.
Varsayılan olarak explain() “queryPlanner” modunda çalışır; ancak farklı modlar da vardır: “executionStats” ve “allPlansExecution”.

Nic Raboy , MongoDB'de Geliştirici İlişkileri Lideridir ve MongoDB'yi projelerine dahil etmelerinde geliştiricilerin başarılı olmasına yardımcı olacak harika içerikler üreten Python, Java, C# ve PHP geliştiricilerinden oluşan bir ekibi yönetir. Golang ve JavaScript konusunda deneyime sahiptir ve sık sık geliştirme maceraları hakkında yazılar yazar.
Öne Çıkan DataCamp Kursları
Kurs
Kurs

blog
Abid Ali Awan
14 dk.
blog
Dario Radečić
15 dk.
Eğitim
Kurtis Pykes
8 dk.
Eğitim
Adel Nehme