2013-05-09 20 views
6

Mam kolekcję MongoDB o nazwie post z 35 milionów obiektów. Zbiór ma dwa dodatkowe indeksy zdefiniowane w następujący sposób.Zapytanie o powolne zakresy na indeksie wielostronicowym

> db.post.getIndexKeys() 
[ 
    { 
     "_id" : 1 
    }, 
    { 
     "namespace" : 1, 
     "domain" : 1, 
     "post_id" : 1 
    }, 
    { 
     "namespace" : 1, 
     "post_time" : 1, 
     "tags" : 1 // this is an array field 
    } 
] 

Spodziewam się następujące zapytanie, które po prostu filtruje przez namespace i post_time, aby uruchomić w rozsądnym czasie bez skanowania wszystkich obiektów.

>db.post.find({post_time: {"$gte" : ISODate("2013-04-09T00:00:00Z"), "$lt" : ISODate("2013-04-09T01:00:00Z")}, namespace: "my_namespace"}).count() 
7408 

Jednak to trwa MongoDB co najmniej dziesięć minut, aby pobrać wynik i, co ciekawe, to udaje skanowanie obiektów, aby wykonać zadanie zgodnie z funkcją explain.

> db.post.find({post_time: {"$gte" : ISODate("2013-04-09T00:00:00Z"), "$lt" : ISODate("2013-04-09T01:00:00Z")}, namespace: "my_namespace"}).explain() 
{ 
    "cursor" : "BtreeCursor namespace_1_post_time_1_tags_1", 
    "isMultiKey" : true, 
    "n" : 7408, 
    "nscannedObjects" : 69999186, 
    "nscanned" : 69999186, 
    "nscannedObjectsAllPlans" : 69999186, 
    "nscannedAllPlans" : 69999186, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 378967, 
    "nChunkSkips" : 0, 
    "millis" : 290048, 
    "indexBounds" : { 
     "namespace" : [ 
      [ 
       "my_namespace", 
       "my_namespace" 
      ] 
     ], 
     "post_time" : [ 
      [ 
       ISODate("2013-04-09T00:00:00Z"), 
       ISODate("292278995-01--2147483647T07:12:56.808Z") 
      ] 
     ], 
     "tags" : [ 
      [ 
       { 
        "$minElement" : 1 
       }, 
       { 
        "$maxElement" : 1 
       } 
      ] 
     ] 
    }, 
    "server" : "localhost:27017" 
} 

Różnica między liczbą obiektów, a liczba skanów musi być spowodowane przez długościach macierzy bramek (które są wszystkie równe 2). Nadal nie rozumiem, dlaczego filtr post_time nie korzysta z indeksu.

Czy możesz mi powiedzieć, czego może mi brakować?

(pracuję na maszynie schodzenia z 24 rdzeni i 96 GB RAM Używam MongoDB 2.2.3.).

+0

Czy przestrzeń nazw ma bardzo niską liczebność? – Sammaye

+0

Obecnie istnieje tylko jedna odrębna wartość 'namespace', której używam. –

+0

Dlatego MongoDB musi najpierw ograniczyć na pierwszym polu, więc pobiera wszystkie 'my_namespace', a następnie pobiera wszystkie dokumenty między tą datą, itd. Itd., Spróbuj zmienić kolejność indeksów, aby czas post_time był pierwszy. – Sammaye

Odpowiedz

3

Znaleziono moją odpowiedź na to pytanie: Order of $lt and $gt in MongoDB range query

Mój indeks jest multiklawiszem indeks (na tags) i używam kwerendy zakresu (na post_time). Apparently, MongoDB nie może używać w tym przypadku obu stron zakresu jako filtra, więc wybiera klauzulę $gte, która jest pierwsza. Ponieważ mój dolny limit jest najniższą wartością post_time, MongoDB rozpoczyna skanowanie wszystkich obiektów.

Niestety to nie jest cała historia. Próbując rozwiązać problem, stworzyłem także indeksy inne niż różne, ale MongoDB nalegało, aby użyć złego. To sprawiło, że pomyślałem, że problem był gdzie indziej. W końcu musiałem zrzucić indeks wielowarstwowy i utworzyć go bez pola tags. Wszystko jest teraz w porządku.

+0

Dang Nigdy nie wiedziałem, że o '$ gt' i' $ lt' i miltikeys, miłe znalezisko! – Sammaye

+0

Korzystanie z cursor.hint może być również rozwiązaniem, które sprawi, że mongodb użyje innego indeksu (http://docs.mongodb.org/manual/reference/method/cursor.hint/#cursor.hint) – rudi

Powiązane problemy