MongoDB anahtarlandırması

Bölüm:1

MongoDB Anahtarlandırması

 

MongoDB ile çalışmanın en önemli hususlarından biri anahtarlandırmadır (indexing) . Tüm veriyi baştan aşağıya okumak yerine anahtarlandırılmış kısımda arama yapıp ilgili veriyi okumak perfonması çarpıcı bir biçimde artırır.

Anahtarlandırmayı anlamak biraz zor olabilir. Konuya yakından bakalım. Bu makalede beş anahtar türünü ele alacağız:

 

1) Varsayılan anahtar (Default_id index)

2) İkincil anahtar

3) Bileşik anahtar

4) Çoklu anahtar

5) Çoklu bileşik anahtar

 

Üzerinde durulacak başka anahtarlarda vardır ancak karışıklık yaratmamak için biz bunları inceleyeceğiz.

Bir koleksiyon için birden fazla anahtar tanımlayabilmemize rağmen sorgu işlerken bir tek anahtar kullanabiliriz. En uygun anahtar MongoDB tarafından çalışma zamanında seçilir.

Bu makale MongoDB hakkında temel bilgilere sahip olduğunuz (Koleksiyonlar , Dokümanlar vb. Gibi) PHP ve temel sorguları işleyebildiğiniz düşünülerek yazılmıştır. Eğer değilseniz ilk başlayanlar için olan makalelerimizi okumanızı öneririz :

Introduction to MongoDB ve MongoDB Revisited.

Seriler için aşağıdaki yapıya sahip “post” adında 500 dökümandan oluşan bir koleksiyona sahip olduğumuzu düşüneceğiz :

 

01

{

02

    "_id": ObjectId("5146bb52d852470060001f4"),

03

    "comments": {

04

        "0""This is the first comment",

05

        "1""This is the second comment"

06

    },

07

    "post_likes": 40,

08

    "post_tags": {

09

        "0""MongoDB",

10

        "1""Tutorial",

11

        "2""Indexing"

12

    },

13

    "post_text""Hello Readers!! This is my post text",

14

    "post_type""private",

15

    "user_name""Mark Anthony"

16

}

 

Şimdi anahtarlamanın çeşitlerini daha detaylı olarak inceleyelim :

Varsayılan Anahtar

 

MongoDB her bir koleksiyon için varsayılan olarak _id sahasında bir varsayılan anahtar yaratır. Her bir dökümanın öncelikli anahtarı olarak kendine has bir _id sahası vardır. Başka hiç bir anahtarlandırmaya erişilemiyorsa bütün sorgu tipleri için varsayılan olarak kullanılabilir.

Bir koleksiyonda anahtarlamayı görmek için MongoDB terminalini açın ve aşağıdakileri yapın :

 

 

 

 

“getIndexes()” metodu koleksiyonumuz için tüm anahtarları döndürür. Sizin de gördüğünüz gibi _id adında bir varsayılan anahtarımız var. Key kısmı , _id alanında anahtarları ve 1 değeri de artan sırayı ı gösterir. Sıralamayı bir sonraki bölümde öğreneceğiz.

 

İkincil Anahtar

 

id alanı yerine kullanmak isteğimiz durumlar için özel bir anahtar belirtmeliyiz. “username” sahasındaki gönderileri aramak istediğimizi düşünelim. Böyle bir durumda koleksiyonun user_name sahası için özel bir anahtar tanımlamalıyız. Varsayılan anahtar dışındaki bu tip özel anahtarlara ikincil anahtarlar denir.

Anahtarlamanın veri tabanındaki etkilerini görmek için anahtarlamadan önce kısaca sorgu perfonmasını inceleyelim. “Jim Alexandar” olan user_name gönderilerinin hepsini bulmak için bir sorgu çalıştıralım.

 

<?php
// query to find posts with user_name "Jim Alexandar"
$cursor = $collection->find(
    array("user_name" => "Jim Alexandar")
);
//  use explain() to get explanation of query indexes
var_dump($cursor->explain());

Anahtarlama için sık olarak kullandığımız en önemli anahtar explain() dir. Bu metod bize anahtarlama ile ilgili bilgileri döndürür. Yukarıdaki explain() fonksiyonunun çıktısı aşağıda gösterilmiştir :

İncelmeye değer bir kaç önemli anahtar :

 

1) cursor : Sorguda kullanılan anahtarları gösterir. BasicCursor ise kullanılan varsayılan anahtarları gösterir ve MongoDB 'ye tüm koleksiyonu arattırır. İlerliyen anlatımlarda BasicCursor yerine BtreeCursor kullandığımızı göreceksiniz.

 

2) n : Sorgunun döndürdüğü dökümanların sayısını gösterir.(Bu durum için bir döküman)

 

3) nscannedObjects : Sorgu tarafından aranan dökümanların sayısını gösterir.(bu durum için 500 dokümanın tümü arandı) Eğer koleksiyondaki dökümanların sayısı oldukça büyükse bu büyük bir zahmete neden olabilir.

 

4) nscanned : Veri tabanı operasyonu sırasında taranan dökümanların sayısını gösterir.

 

İdeal olarak n yaklaşık nscanned sayısı ile aynı olmalı. Bu da minumun sayıda dökümanın tarandığı anlamına gelir.

Şimdi aynı sorguyu ikincil anahtar kullanarak çalıştıralım. Anahtarı yaratmak için aşağıdaki MongoDB terminali çalıştıralım :

“ensureIndex()” metodunu kullanarak gönderi koleksiyonunda user_name sahası üzerinde anahtar yaratıyoruz. Metoda argüman olarak verdiğimiz sıralama değerini (artansa 1 , azalansa -1) fark etmiş olmalısınız. Bunu daha iyi anlamak için her dökümanda tarih bilgisi sahası olduğunu düşünelim . En güncel gönderileri ilk olarak istiyorsak azalan sırayı kullanmalıyız. En eski gönderileri başta istiyorsak artan sırayı seçmeliyiz.

Bir anahtar yarattıktan sonra daha önceki gibi sorguyu analiz etmek ve çalıştırmak için find() ve explain() metodları kullanılır. Çıktısı :

 

array(15){

[“cursor”]=>string(23)”BtreeCursor user_name_1”

[“isMultiKey”]=>bool(false)

[“n”]=>int(1)

[“nscanned”]=>int(1)

...

 

Çıktı , sorgunun “user_name_1” isimli BtreeCursor kullandığını ve bir dökümanı taradığını gösterir. Bir önceki örnekte 500 dökümanı kullanmıştık.

Tüm MongoDB anahtar algoritmalarında , BTree veri yapılarını kullanılır ve varsayılan cursor olarak BtreeCursor atanır. BtreeCursorlar hakkında detaylı anlatım bu makalemizin amaçı dışındadır ama bu detaylar, anlatılacak konuları anlamanızı engellemezler.

Yukarıda anlatılanlar ,anahtar kullanmanın sorguların performansını nasıl değiştirdiğini gösterir.

 

Bileşik Anahtar

 

Sorgularda birden fazla alanın kullanıldığı durumlarda bileşik anahtarları kullanabiliriz. Aşağıda “post_type” ve “post_like” alanlarının kullanıldığı sorguya göz atalım :

 

<?php
// query to find posts with type public and 100 likes
$cursor = $collection->find(
    array(
        "post_type" => "public",
        "post_likes" => 100
    ),
    array()
);

“explain()” ile sorguyu analiz edince 500dökümanın tarandığı ve usesBasicCursor sorgusunu gösteren bir çıktı verir.

 

array(15){

["cursor"]=>string(11) "BasicCursor"

["n"]=>int(1)

["nscanned"]=>int(500)

 

Bu gerçekten çok verimsiz olduğu içn anahtarlandırma uygulayarak bu durumu düzeltmeye çalışalım. Fieldpost_type ve post_likes üzerinde aşağıdaki gibi bir bileşik anahtar uygulayalım :

 

Sorguyu analiz ettiğinizde gösterilen sonucu verir :

 

array(15){

["cursor"]=>string(36) "BasicCursor"

["n"]=>int(1)

["nscannedObjects"]=>int(1)

["nscanned"]=>int(1)

 

Burada dikkat edilecek en önemli nokta birden fazla alanda tanımlanan bileşik anahtarlar, bu alanların alt kümelerini sorgulamak için de kullanılabilir.

 

  • alan1

  • alan1 , alan 2

  • alan1 , alan2 , alan3

 

Böylece eğer {alan1,alan2,alan3} anahtarını tanımladıysak , ayrı ayrı {alan1} ve {alan1,alan2} anahtarlarını tanımlamamıza gerek yoktur. Ancak , bu bileşik anahtara alan1 ,alan2 , alan3 sorgularını yaparken ihtiyaç duyarsak ,iyileştiricimiz istenen anahtarı seçmediyse , hint() kullanabiliriz.

“hint()” metodu MongoDB 'yi tanımladığımız anahtarı kullanmaya ve varsayılan seçimlerin üzerine yazmaya zorlar. Anahtarda kullanılan alan isimlerini örnekteki gibi argüman olarak tanımlayabilirsiniz :

 

<?php
// query to find posts with type public and 100 likes
// use hint() to force MongoDB to use the index we created
$cursor = $collection
    ->find(
        array(
            "post_type" => "public",
            "post_likes" => 100
        )
    )
    ->hint(
        array(
            "post_type" => 1,
            "post_likes" => 1
        )
    );

Bu sorgunun post_type ve post_likes üzerinde bileşik anahtar kullanmasını garanti eder.

 

 

Çoklu Anahtar

 

Anahtarlandırma eğer dizi alanında yapılıyorsa bu çoklu anahtar olarak adlandırılır. “post” dökümanımızı tekrar düşünün ; “post_tags”e çoklu anahtarı uygulayabiliriz. Çoklu anahtar, dizideki her elemanı anahtarlandıracaktır. Böylece , “post_tags” değerleri için ayrık anahtarlar yaratılır : MongoDB , Tutorial ; Indexind vb...

 

Dizideki anahtarlar çok seçici kullanılmalıdır çünkü her eleman anahtarlandırıldığı için hafızada oldukça yer kaplarlar.

 

Çoklu Bileşik Anahtar

 

Ancak alandaki en fazla bir elemanın dizi olması durumunda çoklu bileşik anahtar yaratabiliriz. Yani , eğer elimizde alan1 katarı ve [alan2 , alan3] dizisi varsa , {alan2 ,alan3} anahtarı yaratamayız çünkü iki alanda dizide.

Aşağıdaki örnekte post_tags ve user_name alanlarında bir anahtar yarattık :

Anahtarlandırma Sınırlandırma ve Düşünceleri

 

Düzenli ifadelerde, olumsuzluk ifadelerinde($ne,$not...), aritmetik operasyonlarda($mod), JavaScript ifadelerinde ve bazı başka durumların sorgularında anahtarlandırma kullanamayacağımızı bilmeliyiz.

Anahtarlandırma operasyonları aynı zamanda kendi bedelleri ile gelir. Her anahtar görevi fazladan masraf , güncelleme , silme ve ekleme operasyonlarına neden olur. Her koleksiyon için yazma ve okuma oranını düşünmelisiniz. Anahtarlandırma; yazma ağırlıklı olan koleksiyonlarda yararlıyken okuma ağırlıklı olanlarda olmayabilir.

MongoDB anahtarları RAM'de saklar. Toplam anahtar boyutunuzun RAM limitini aşmadığından emin olmalısınız. Ayrıca bir koleksiyon maksimum 64 anahtar içerebilir.

 

Özet

Bu bölüm için bu kadar. Özetle eğer doğru anahtar tekniği seçilirse , bir uygulama için oldukça yaralıdır. Bir sonraki bölümümüzde , gömülü dökümanların(embeded documents) ve alt-dökümanların(sub-documents) indexlenmesini ve sıralanmasını inceleyeceğiz.

 

 

Bölüm : 2

Yazımızın birinci bölümünde MongoDB ile anahtarlandırmaya giriş yaptık ve anahtarları nasıl yaratıp kullanacağımızı ve verilen bir anahtar sorgusunun nasıl yapılacağını analiz ettik. Bu bölümümüzde gömülü alanlar, alt dökümanlar, örtük sorgular ve anahtar yönleri gibi daha küçük ancak önemli içeriklere göz atacağız. Tabiki bu bölümde bir anahtarı nasıl yaratacağınızı bildiğinizi ve analiz etmek için “explain()” metodunu kullanabildiğinizi varsaydık. Eğer bunları bilmiyorsanız bir önceki bölümden başlayarak devam etmenizi öneririz.

İlk sayfamızda “post” isimli bir koleksiyon kullanmıştık. Şimdi gönderimizin yapıldığı yeri saklayabilmemiz için location alanı ekleyelim . Bu alan bir alt dökümandır ve aşağıda gösterildiği gibi kullanıcının şehir, eyalet , ülke özelliklerini saklar.

 

{
    "_id": ObjectId("5146bb52d852470060001f4"),
    "comments": {
        "0": "This is the first comment",
        "1": "This is the second comment"
    },
    "post_likes": 40,
    "post_tags": {
        "0": "MongoDB",
        "1": "Tutorial",
        "2": "Indexing"
    },
    "post_text": "Hello Readers!! This is my post text",
    "post_type": "private",
    "user_name": "Mark Anthony",
    "location": {
        "city": "Los Angeles",
        "state": "California",
        "country": "USA"
    }
}

Alt Dökümanlarda Anahtarlandırma

 

Kullanıcının nerede yaşadığı bilgisini içeren gönderiyi bulmak istediğimizi varsayalım. Bunun için alt dökümanımız olan location alanında bir anahtar yaratmalıyız. Daha sonra örnekteki tarz bir sorguyu yapabilmek için anahtarımızı kullanalım:

 

<?php
// query to find posts from the city of Los Angeles
$cursor = $collection->find(
    array(
        "location" => "Los Angeles"
    ),
    array()
);

// query to find posts from the state of California
$cursor = $collection->find(
    array(
        "location" => "California"
    ),
    array()
);

// query to find posts from the United States
$cursor = $collection->find(
    array(
        "location" => "USA"
    ),
    array()
);

 

“location” kullanarak alt dökümanın alt alanlarında (city ,state ,country) arama yapabiliriz. Sorgu , “location” alt alanları ile aradığımız kriterlerin uyuşup uyuşmadığını kontrol eder.

Dizilerde anahtarlandırma yapılırken olduğu gibi her bir alt alana ayrı anahtar verildiğine dikkat edilmelidir. Bu durum için location.city , location.state , location,country olarak üç adet anahtar yaratıldı. Bu anahtarların hafızada yer kapladığını unutmamalıyız.

 

 

Gömülü Alanlarda Anahtarlandırma

 

Alt döküman alanlarının hepsini anahtarlamaya ihtiyaç olmadığı zaman kullanılır. Örneğimizde sadece şehir ile alakalı gönderileri aramak isteseydik gömülü alandaki “city” elemanını anahtarlıyacaktık.

 

Şimdi bu anahtarı şehir gönderisini bulmak için kullanabiliriz:

 

<?php
// query to find posts from the city of Los Angeles
$cursor = $collection->find(
    array(
        "location.city" => "Los Angeles"
    ),
    array()
);

Anahtar Yönü(Artan/Azalan)

 

Şu ana kadar anahtarlarımızı yaratırken artan veya azalan olduğunu belirtmek için 1 veya -1 kullandık. Birinci bölümde buna değinmiştik ancak önemli bir konu olduğu için tekrar bahsetmekte yarar görüyorum. Eğer anahtarımızda, arama yaparken kullanabileceğimiz özel olan alanların sayısı bir ise (primary key sayısı), yönün 1 veya -1 olması farketmez ama birleşik anahtar kullanarak sorguları sıralama veya puanlandırmada fark eder.

Düşelim ki ; alan1(field1) artan ve alan2(field2) azalan sırada olan birleşik anahtarımız var. Böyle bir durumda anahtarlandırılmış tablomuz şekildeki gibi görünecektir :

satır      alan1     alan2

 

Alan1 'i artan , alan2'yi artan olarak sıralayan bir sorgu sırayla şu satırları gezicektir : 1, 2, 3, 4, 5, 6, 7, 8, 9. Alan1'i artan , alan2'yi azalan kabul eden sorgu ise şu sırayla gezer: 3, 2, 1, 6, 5, 4, 9, 8, 7. Bu gibi arama ağacındaki düzensiz sıçramalar sorgunun perfonmasını kötü yönde etkiler. Tabi bu örnekteki tablo sadece olayı anlamanız için bu şekilde verilmiştir. MongoDB içsel bir ağaç yapısı kullanır; her eleman ağaçın bir düğümü olarak depolanır. Aynı dal altındaki elemanlar birbirlerine yakınlardır böylece kolayca yaklaşılabilirler. Eğer bir sorgu sıralı tarzda birden fazla kayıt yapmak zorundaysa , elemanları ağaç üzerinde birbirlerine yakın tutmak mantıklı olucaktır.

Eğer alan1:1 , alan2:1 sıralamasına bakıyorsanız , anahtar {alan1:1 , alan2:1} , {alan1:1 , alan2:1} veya {alan1:-1, alan2:1} anahtarından daha hızlı olucaktır.

 

Örtülü Sorgular

 

MongoDB dökümanlarına göre örtülü sorgu olma durumu :

 

  • Sorguda kullanılan tüm alanlar yine sorguda kullanılan anahtarların birer parçalarıdır.

  • Tüm alanlar aynı anahtar üzerinden sonuç döndürürler.

 

Tüm alanlar anahtarı kendi başlarına karşıladıkları için , MongoDB sorgu şartları ile eşleşebilir ve dökümanın içine bakmadan aynı anahtarı kullanarak sonuç alanlarına dönebilirler. Anahtarlar RAM üzerinde veya sıralı bir şekilde diskte saklandıkları için onlara ulaşmak daha hızlıdır.

post_type ve user_name alanları olarak bağlı anahtarlarımız olduğunu düşünelim. Bu anahtar aşağıdaki sorguyu karşılar :

 

 

<?php
// query to find posts with type public and get only user_name in result
$cursor = $collection->find(
    array(
        "post_type" => "public",
    ),
    array(
        "user_name" => 1,
        "_id" => 0
    )
);

 

Açık bir şekilde _id alanını sonuçtan uzakta tuttuk. Bunun nedeni ise örtülü sorguyu bir avantaj haline getirebilmektir. Daha önceden de bildiğimiz gibi _id alanına dönen tüm sorgular varsayılan olarak atanır. Örtülü sorguların ikinci şartına göre , sonuca dönen tüm alanlar anahtara eklenmiş olmalı. Birleşmiş anahtarımızda _id yok, bu yüzden sonucumuzdan bu kısmı çıkartmalıyız.

Bir sorgunun örtülü olup olmadığını kontrol etmek için explain() sonucundaki indexOnly alanına bakabiliriz. True sonucu bize örtülü sorgu olduğunu gösterir.

Bir anahtarın sorguyu örtemeyeceği bazı durumlar :

  • Anahtardan herhangi birinin dizi olması(post_tag gibi)

  • Anahtarlardan herhangi birisinin alt döküman alanı olması.

 

Anahtarlandırmayı Kaldırmak

 

Veri tabanında o anki büyüklüğü kontrol etmek için bit olarak toplam anahtar boyutunu döndüren totalIndexSize() fonksiyonunu kullanabiliriz.

 

Anahtarları yerleştirmek ve MongoDB 'nin düzenli olarak kullanıp yönettiği verileri saklayabilmek için RAM üzerinde yeterli yere sahip olduğunuzdan emin olmalısınız.

Bir anahtarı silmek ve kaynakları serbest bırakmak için dropIndex() metodunu kullanabilirsiniz.

 

 

Sonuç

 

MongoDb doğru anahtarlandırma ile hızı yükseltmek için önemli konulara değindik. Anahtarınızı analiz ederken , uygulamalarınız büyürken ve verileriniz değişirken işlerini hala doğru bir şekilde yapıyor olduklarından emin olun. 

04.07.2013
Okunma sayısı: 5662

YORUMLAR

Bu sayfalarda yer alan okur yorumları kişilerin kendi görüşleridir. Yazılanlardan Sanal Yazılım Ltd. veya sanal.mobi sorumlu tutulamaz.