2014-07-22 15 views
6

Mam ponad 600 000 rekordów w MongoDb. moim schemacie użytkownik wygląda następująco:Projekcja sprawia, że ​​zapytanie wolniejsze

{ 
    "_id" : ObjectId, 
    "password" : String, 
    "email" : String, 
    "location" : Object, 
    "followers" : Array, 
    "following" : Array, 
    "dateCreated" : Number, 
    "loginCount" : Number, 
    "settings" : Object, 
    "roles" : Array, 
    "enabled" : Boolean, 
    "name" : Object 
} 

następujące zapytanie:

db.users.find(
    {}, 
    { 
     name:1, 
     settings:1, 
     email:1, 
     location:1 
    } 
).skip(656784).limit(10).explain() 

wyniki w to:

{ 
    "cursor" : "BasicCursor", 
    "isMultiKey" : false, 
    "n" : 10, 
    "nscannedObjects" : 656794, 
    "nscanned" : 656794, 
    "nscannedObjectsAllPlans" : 656794, 
    "nscannedAllPlans" : 656794, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 5131, 
    "nChunkSkips" : 0, 
    "millis" : 1106, 
    "server" : "shreyance:27017", 
    "filterSet" : false 
} 

i po usunięciu projekcja samego zapytania db.users.find().skip(656784).limit(10).explain()

wyniki w tym :

{ 
    "cursor" : "BasicCursor", 
    "isMultiKey" : false, 
    "n" : 10, 
    "nscannedObjects" : 656794, 
    "nscanned" : 656794, 
    "nscannedObjectsAllPlans" : 656794, 
    "nscannedAllPlans" : 656794, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 5131, 
    "nChunkSkips" : 0, 
    "millis" : 209, 
    "server" : "shreyance:27017", 
    "filterSet" : false 
} 

O ile wiem, projekcja zawsze zwiększa wydajność zapytania. Nie jestem w stanie zrozumieć, dlaczego MongoDB zachowuje się w ten sposób. Czy ktoś może to wyjaśnić? A kiedy użyć projekcji, a kiedy nie. I jak właściwie projekcja jest zaimplementowana w MongoDB.

+1

Czy otrzymujesz te wyniki wielokrotnie? Drugie zapytanie może być szybsze tylko dlatego, że dane są buforowane (ładowane do pamięci) z pierwszego zapytania. – Messa

+0

Ponieważ stosuje się projekcję do dokumentów 656794 – Sammaye

+0

, ale dlaczego stosuje ona projekcję do dokumentów 656794, jest to bardzo błędna implementacja. Potrzebuję tylko 10 rekordów, więc projekcja powinna być zastosowana tylko do 10 dokumentów. –

Odpowiedz

4

Masz rację, że projekcja spowalnia kwerendę pominięcia w MongoDB 2.6.3. Jest to związane z problemem dotyczącym optymalizacji z narzędziem planowania zapytań 2.6, oznaczonym jako SERVER-13946.

Planer zapytań do 2.6 (w wersji 2.6.3) dodaje etapy SKIP (i LIMIT) po analizie projekcji, więc rzutowanie jest niepotrzebnie stosowane do wyników, które są odrzucane podczas przeskakiwania dla tego zapytania. Przetestowałem podobne zapytanie w MongoDB 2.4.10, a nScannedObjects było równe liczbie wyników zwróconych przez mój limit, a nie skip + limit.

Istnieje kilka czynników przyczyniających się do wykonywania zapytań:

1) nie określono żadnych kryteriów zapytania ({}), więc ta kwerenda robi skanowanie zbiórki w natural order zamiast używać indeksu.

2) Zapytanie nie może zostać zakryte, ponieważ nie ma projekcji.

3) Masz wyjątkowo dużą wartość skip wynoszącą 656,784.

Jest na pewno miejsce na ulepszenie planu kwerend, ale nie spodziewałbym się, że wartości pominięcia tej wielkości będą rozsądne w normalnym użytkowaniu. Na przykład, jeśli było to zapytanie aplikacji o paginację z 50 wynikami na stronę, twoja wartość skip() byłaby odpowiednikiem strony o wartości 13,135.

+1

Rzeczywiście ten skip nie jest wykonalny, ale jest to dobre znalezisko, mam nadzieję, że zostanie to naprawione wkrótce, ponieważ może oznaczać, że nawet małe skoczki będą musiały wykonać dodatkową pracę, niż potrzeba – Sammaye

1

ile wynikiem projekcji robi coś, aby przygotować „tylko wskaźnik” zapytanie, a to oznacza tylko pola „przewidywana” w rezultacie są wszystko obecny w indeksie tylko, to jesteś zawsze produkuje więcej pracuje dla silnika zapytań.

Trzeba rozważyć proces:

  1. Jak dopasować? Na dokumencie lub indeksie? Znajdź odpowiedni podstawowy lub inny indeks.

  2. Biorąc pod uwagę indeks, skanuj i znajduj rzeczy.

  3. Co mam teraz zwrócić? Czy wszystkie danych w indeksie? Jeśli nie, wróć do kolekcji i wyciągnij dokumenty.

To jest podstawowy proces. Jeśli więc jeden z tych etapów nie "optymalizuje" w żaden sposób, rzeczy oczywiście "trwają dłużej".

Trzeba spojrzeć na to, projektując "silnik serwera" i zrozumieć kroki, które należy podjąć. Biorąc pod uwagę, że żaden z twoich warunków nie spełnił niczego, co by wyprodukowało "optymalny" w określonych krokach, musisz nauczyć się to akceptować.

Twój "najlepszy" przypadek, jest tylko wyświetlane pola są polami obecnymi w wybranym indeksie. Ale tak naprawdę nawet to ma na celu załadowanie indeksu.

Wybieraj mądrze i poznaj wymagania dotyczące ograniczeń i pamięci dla tego, o co pytasz. O to właśnie chodzi w "optymalizacji".

+2

Nie sądzę, że to wyjaśnia, dlaczego MongoDB wygląda tak, jakby wyświetlał się w dokumentach 656784, które może liczyć z _id indeksem – Sammaye

+1

@NeilLunn Rozumiałem twój punkt widzenia. Ale zgadzam się również z Sammaye "dlaczego mongo stosuje projekcję do każdego dokumentu" powinno stosować projekcję tylko do powracających dokumentów. –

+0

@ShreyanceJain ** dłuższe ** wyjaśnienie, co to jest "projekcja" w kontekście, gdzie nie jest to " index only ", a zatem" picking "z pól w indeksie faktycznie wymaga zrozumienia operatora' $ project' z potoku struktury agregacji i zrozumienia przetwarzania silnika zapytań. Zasadniczo w innych przypadkach prosi się o "przekazanie" wszystkich dokumentów i "zmianę kształtu". Czy to wymaga dalszego wyjaśnienia? –

Powiązane problemy