2012-04-18 11 views
7

Zdarzenia kolekcji mają identyfikator użytkownika i tablicę zdarzeń - każdy element w tablicy jest osadzonym dokumentem. Przykład:mongodb - indeks daty nie jest używany

{ 
    "_id" : ObjectId("4f8f48cf5f0d23945a4068ca"), 
    "events" : [ 
      { 
        "eventType" : "profile-updated", 
        "eventId" : "247266", 
        "eventDate" : ISODate("1938-04-27T23:05:51.451Z"), 
      }, 
      { 
        "eventType" : "login", 
        "eventId" : "64531", 
        "eventDate" : ISODate("1948-05-15T23:11:37.413Z"), 
      } 
    ], 
    "userId" : "junit-19568842", 

}

Korzystanie z kwerendy jak poniżej jednego tofind zdarzeń generowanych w ciągu ostatnich 30 dni:

db.events.find({ events : { $elemMatch: { "eventId" : 201, 
"eventDate" : {$gt : new Date(1231657163876) } } } } ).explain() 

planu kwerend pokazuje, że wskaźnik na "events.eventDate" jest używany, gdy Wyniki badań zawiera mniejszą liczbę zdarzeń (około 20)

{ 
    "cursor" : "BtreeCursor events.eventDate_1", 
    "nscanned" : 0, 
    "nscannedObjects" : 0, 
    "n" : 0, 
    "millis" : 0, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : true, 
    "indexOnly" : false, 
    "indexBounds" : { 
      "events.eventDate" : [ 
        [ 
          ISODate("2009-01-11T06:59:23.876Z"), 
          ISODate("292278995-01--2147483647T07:12:56.808Z") 
        ] 
      ] 
    } 

}

Jednak, gdy istnieje duża liczba zdarzeń (około 500), indeks nie jest używany:

{ 
    "cursor" : "BasicCursor", 
    "nscanned" : 4, 
    "nscannedObjects" : 4, 
    "n" : 0, 
    "millis" : 0, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : false, 
    "indexOnly" : false, 
    "indexBounds" : { 

    } 

}

Dlaczego indeks nie jest używany, gdy istnieje wiele zdarzeń? Może być, gdy jest duża liczba zdarzeń, MongoDB stwierdza, że ​​jest skuteczny tylko do skanowania wszystkich przedmiotów niż przy użyciu indeksu?

+0

Skarżysz się, że optymalizator nie używa indeksu dla zapytania, które zajęło 0 ms, aby powrócić? :) –

+0

Powyższy wynik wyjaśnienia pochodzi z kolekcji testów. Przy około 20 milionach dokumentów zapytanie trwało około 8 sekund. – dsatish

+0

Takie zapytania zakresu mogą być powolne, jeśli pytasz znaczną część dokumentów kolekcji. Możesz użyć wskazówki, aby wymusić indeks w celu porównania prędkości, ale wyobrażam sobie, że będzie równie powolny podczas skanowania indeksu. Powinieneś zamieścić wyjaśnienie na swoich danych produkcyjnych, z podpowiedziami i bez nich. Chodzi o to, że jeśli znajdziesz kilka milionów dokumentów, które pasują, zajmie to trochę czasu, aby je sprawdzić. –

Odpowiedz

11

Optymalizator zapytań MongoDB działa w specjalny sposób. Zamiast obliczać koszt określonego planu zapytań, uruchamia on wszystkie dostępne plany. To, co nastąpi wcześniej, jest uważane za optymalne i będzie używane w przyszłości.

Aplikacja rośnie, dane rosną i zmieniają się, optymalny plan może nie być optymalny w pewnym momencie. Tak więc mongo powtarza ten proces selekcji zapytań co jakiś czas.

Wygląda na to, że w tym konkretnym przypadku skanowanie podstawowe było najbardziej wydajne.

Link: http://www.mongodb.org/display/DOCS/Query+Optimizer

2

Korzystanie $ podpowiedź, aby wymusić użycie indeksu "events.eventDate", to nscannedObjects jest więcej niż w/o indeksie.

Pseudo kod przy użyciu indeksu:

for(all entries in index matching the criteria) { 
    get user object and scan to see if the eventId criteria is met 
} 

wszystkie wpisy w indeksie dopasowania kryteriów -> każde zdarzenie jest wpis w indeksie. Tak więc liczba wpisów w indeksie będzie większa niż liczba użytkowników. Powiedzmy, że istnieją 4 obiekty użytkownika i łącznie 7 zdarzeń spełniających kryteria, obiekt użytkownika jest skanowany 7 razy (pętla wykonywana jest 7 razy). Gdy indeks nie jest skanowany, wszystkie 4 obiekty użytkownika są sprawdzane tylko raz. Tak więc przy użyciu indeksu liczba razy, gdy obiekt użytkownika jest skanowany, jest większa niż wtedy, gdy nie korzysta się z indeksu. Czy to zrozumienie jest właściwe?

db.events.find({ events : { $elemMatch: { "eventId" : 201, 
"eventDate" : {$gt : new Date(1231657163876) } } } } ) 
._addSpecial("$hint",{"events.eventDate":1}).explain() 

{ 
    "cursor" : "BasicCursor", 
    "nscanned" : 7, 
    "nscannedObjects" : 7, 
    "n" : 0, 
    "millis" : 0, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : false, 
    "indexOnly" : false, 
    "indexBounds" : { 

} 
Powiązane problemy