7. MongoDb – Indexing Konsepti

Indexing tüm database konseptleri için olduğu gibi MongoDb için de son derece önemlidir. Veri seti üzerinde doğru Indexing kullanıldığı zaman, MongoDd donanımı verimli bir şekilde kullanabilir ve uygulamanın querylerini hızlı bir şekilde sonuçlandırabilir. Ancak yanlış Indexing de tam tersi bir sonuç verir; yavaş query ve write operasyonarı ve verimli kullanılamayan donanım… MongoDb’yi etkin bir şekilde kullanmak isteyen herkesin indexingi anlaması gerekir.

MongoDB’de indexing yapısını araştırıyorsanız artık normal indexing yapısını az çok bildiğinizi varsayıyorum. Relational databaselerde olduğu gibi MongoDb’de de indexingin amacı query performansını artırmaktır. Index olmadan yapılan bir search’te MongoDd tüm collection’ı baştan aşağı scan edip arama ihtiyacı duyarken, indexing datayı sorted tuttuğu için, MongoDB sadece index scan yapar. 

1.SINGLE-KEY INDEX ve COMPOUND-KEY INDEXES

MongoDb indexleme için B-Tree data structure’ını kullanır. Çünkü B-tree data structure’ı yapısı gereği indexing işlemleri için çok idealdir. B-Tree veri yapısı, aslında indexingten de bağımsız, veri yapıları içerisinde ayrı bir konu olduğundan bu yazıda detaylıca girmeyeceğim. Yazılının devamında indexing kategorilerinin en geneli olan single-key ve compound-key index ile devam edeceğim.

1.1.SINGLE-KEY INDEXES

Single-key indexing’de, indexteki her entry  indexlenen dökumanda sadece bir değerine karşılık geldiği index gelir. Default olarak gelen _id single key için güzel bir örnektir.

1.2.COMPOUND-KEY INDEXES

Bazen birden çok field’ı içeren query çalıştırmanız gerekebilir ve bunu da maksimum performans ile yapmak isteyebilirsiniz. Bunun için bir e-ticaret örneğinden devam edelim. Manufacturer ve sales prices adında iki adet collectionumuz olduğunu varsayalım. Bu collectionların ikisi içinde single key index oluşturduğumuz takdirde indexing tablelar aşağıdaki gibi birbirinden tamamen bağımsız olacaktır ve aşağıdaki gibi bir sorgulama yaptığımızda query optimizer bu iki single-key indexin best performansa sahip olanını seçecektir. Ancak bu iki single-key indexingin best performanslı olanı dahi size tam optimize bir sonuç vermez. Çünkü bu indexler içerisinden best performansa sahip olanı seçebilmek için optimizerın iki yapıyı da ayrı ayrı traver etmesi, eşleşen disk locasyonlarını tutması ve intercetion alması gerekir.

db.product.find({ 'details.manufacturer':'Acme'},
                 $lt:7500
               )

Compound-key indexing de tam da bu noktada devreye giriyor. Compound key birden fazla entryinin bir index key’e karşılık geldiği indexing yapısıdır.  Buna göre aşağıdaki gibi compound index kullanıldığında maximum performans ile arama yapabiliriz.

Ancak burda dikkat edilmesi gereken bir durum var. İndexlenen entrylerinin sırası. Indexlemeyi aşağıdaki gibi Price-Manufacturer şeklinde yaptığımız zaman sorgu performansı oldukça azalacaktır. Genel bir kural olarak da, eğer ki sorgunuz bir exact match bir de range query içeriyorsa, exact match her zaman öne alınır.

Genel olarak bir kaç index rule’ını sıralarsak,

1. Indexler, document’ları sorgulamak için gereken execution time’ı önemli ölçüde azaltır. Uygun index olmadan, bir sorguyu sonuçlandırmanın tek yolu, sorgu koşulları karşılanana kadar tüm documentları uçtan uca taramaktır. 
2. Eğer “a” fieldınız içeren bir indexiniz var ise sonrasında “a-b” yi içeren bir compound index tanımlarsanız “a” indexi geçersiz ve gereksiz olacaktır. Ancak bu “b-a” şeklinde tanımlanan compound indexi için geçerli değildir.
3. Compound indexingte sıralama önemlidir. Sorgunuz bir exact match bir de range query içeriyorsa, exact match her zaman öne alın.

2.INDEX SORGULAMA

Aşağıdaki queryler ile indexlerimizi sorgulayabiliriz.

db.tax.getIndexes()

db.getCollection('name').getIndexes()

3. INDEXING MALIYETI

İndexleme işlemi query performansı için olmazsa olmaz olsa da, her indexleme işleminin ufak sayılabilecek costları da vardır. İndexing disk maliyetini artırır ve write hızını azaltır.  Ancak read-intensive uygulamalarda, indexlemenin maliyeti genelde yok sayılabilecek düzeydedir. Sadece yarattığınız tüm indexlerin kullanılabilir, gerekli ve tekrarsız olmadığından emin olmanız yeterli olabilir.

4.INDEX TIPLERI

2.1. UNIQUE INDEX

İsminden de anlaşıldığı üzere indexlediğiniz alanın uniqueliğini garanti ettiğiniz index tipidir. Eğer var olan index ile tekrar bir data eklemek isterseniz fail alacaksınız.

db.users.createIndex(  {index: 1}, {unique : true} )

Eğer böyle bir indexinge ihtiyacınız var ise data documentları eklemeden indexingi yapmanız koşulu ile zorunlu hale getirecek ve eklenen dokümanları consistent tutacaktır.

2.2. SPARSE INDEX

İndexler default olarak dense yapıdadır. Ancak dense yapıdaki indexlerde iki istenmeyen durumla karşılaşmamız olasıdır.  İlk olarak, dense yapıdaki index’e null bir değer insert ettiğinizde problem olmayacaktır. Ancak indexi unique hale getirdiğinizde ikinci null alanı insert ettiğinizde hata alacaksınız.

db.products.createIndex(  {sku:1} , {unique:true,  sparse:true } )

.Bir diğer sıkıntı da elinizdeki collectionun ilgili bir çok datası null ise performans kaybı yaratacaktır. Sparse index sadece indexlenen alanı dolu olan dökümanları alan null olsa dahi içerir. Ancak index, indexlenen alan olmayan dökümanları pas geçer. Index sparse index olarak adlandırılır çünkü dökümanın tüm koleksiyonlarını içermez. 

db.reviews.createIndex( {  user_id:1}, { sparse : true, unique : false  })

Sonuç olarak sparse indexler, ilgili alanı bulunmayan dökümanları içermezler. Ancak bu alan var ve null ise hala indexlenebilirdir. Bu noktada, ilgili alanın sizin dökümanınızda olmaması ve olması ancak o alanın null olarak kayıtlı olması arasındaki seçimi yapmanız gerekir. Sparse indexing’e çok sayıda dökümanınız olduğu ve bunların küçük bir kısmının ilgili alanı içerdiği durumlarda ihtiyaç duyarsınız. Bu noktada normal index yaratmak maliyetlidir çünkü RAM’i ilgilenmediğiniz dökümanları indexlemede kullanırsınız.

2.3. MULTIKEY INDEXES

MongoDB array dataları için de arraydeki her bir eleman için index key’i yaratarak indexleme yapmayı destekler. Bu tip indexler multikey index olarak adlandırılır ve arrayler üzerinde efficient arama yapmayı sağlar. Aynı zamanda bu indexing hem scalar value içeren arraylerde hem de nested dökümanlarda kullanılabilir.

{
  name : ""Wheelbarrow",
  tags : ["tools","gardening","soil"]
}

Eğer tags üzerinden bir indexleme yaparsnız, tags arrayındaki tüm değerler indexte gözükecektir. Bunun anlamı arraydeki herhangi bir index olarak dokumanı point edebilirdir.

Multikey index ile ilgili bazı önemli noktalar

  • İndexlediğiniz alan bir array ise, mongo db bu alan için otomatik olarak multikey index üretecektir.
  • Mongodb’de hashed indexler multikey index değildir.
  • Mongodb’de, filter query, array için tüm elemanlar bazında exact match içeriyorsa, öncelikle multikey indexi ilk eleman bazında array. Sonrasında ilk elemanı eşleşen tüm elemenları toplar. Daha sonra bunları queryde eşleşen koşullar ile filtreler. Yani direkt olarak tüm elemanları eşlemez
db.Collection_name.createIndex({filed_name: 1/ -1})
2.4. HASHED INDEXES

Normal durumda MongoDb’nin indexing için B-tree yapısını kullanıldığını söylemiştik. B-tree yapısıyla inşaa edilen indexlerde örneğin, “Apple Pie” entrysi “Artichoke Ravioli” entrysinin yanında konumlanır. Ancak hashed indexing kullanıldığında entryler ilk olarak hash functinonun içerisinden geçer. Bu da hashed valueların sırayı belirleyeceği anlamına gelir.

db.recipes.createIndex( { recipe_name:'hashed'} )

tabi hashed indexing bazı kısıtlamaları da vardır.

  1. Equality querylerde çalışır ancak range queryleri desteklemez.
  2. Multikey hashed indexes yoktur.
  3. Floating point valuelar hashlenmeden önce integera set edilir.

Peki hased index kullanmanın amacı nedir? hashed indeteki entryler eşit larak dağıtılır. Diğer bir deyişle normalde non-uniform dağılmış key datalarınız vardır. Hashed set uniformity yaratır. Bu da sharded collectionlarda faydalıdır. 

Önemli Noktalar

İndex yaratmak zaman alan bir işlemdir. Özellikle productionda daha da sıkıntı yaratan bir hal alabilir ki index creation operasyonunun kolayca kill edilebilen bir operasyon değlidir. En mantıklı yaklaşım bu işe bir database migrasyonu gibi davranmaktır.

Index oluşturma iki stepte oluşur.

Birinci aşama indexlenecek value’lar sıralanır. Bu sort edilen B-treeye çok daha rahat ve efficient insert edilebilir.

İkinci aşama ise sort edilen valueların index içerisine insert edilmesidir.

5. INDEX SILME

Default indexleri silemeyiz ancak diğer indexler için aşağıdaki queryleri kullanabiliriz.

db.collection.dropIndex({:1})

db.collection.dropIndexes()  hepsini siler

FAYDALI LINKLER

https://www.stackchief.com/blog/Compound%20Index%20%7C%20MongoDB%20Indexing%20Tutorial

https://www.percona.com/blog/2018/12/19/using-partial-and-sparse-indexes-in-mongodb/