Różnica między szukaniem MongoDB a szukaniem findone


34

Pracuję nad projektem i nie jestem pewien, czy istnieje różnica między sposobem działania findkursora a działaniem findOnekursora. Czy findOne to tylko opakowanie find().limit(1)? Rozglądałem się i może ktoś wie, czy mongodb ma do tego specjalną metodę, czy nie. Pracuję z PHP API dla mongodb, jeśli to robi różnicę.

Odpowiedzi:


33

W oparciu o moje własne testy porównawcze find().limit(1)jest o rząd wielkości szybszy niż findOne().

Wystąpił błąd w dokumentacji MongoDB lub błąd w findOne(). findOne()działa bardziej jak find().limit(N)gdzie N to liczba dokumentów, które zwróci zapytanie. Zrozumiałem to, próbując dowiedzieć się, dlaczego moje proste zapytania były tak wolne!

aktualizacja: odpowiedź inżyniera 10gen (MongoDB):

Dwa wykonywane zapytania są bardzo różne. Zapytanie wyszukujące zwraca kursor, jest to zasadniczo scenariusz braku operacji, ponieważ żadne rzeczywiste dane nie są zwracane (tylko informacje o kursorze). Jeśli wywołasz findOne, w rzeczywistości zwracasz dane i zamykasz kursor. Dokumenty powinny zdecydowanie być jaśniejsze :-)

Aktualizacja: Rzeczywiście, jeśli find().limit(1)dokument zostanie pobrany, wydaje się, że różnica prędkości rzędu rzędów zniknie. Ponadto nie mogłem odtworzyć głównej różnicy prędkości ze sterownikiem JavaScript MongoDB. Początkowo testowałem przy użyciu sterownika Java MongoDB.


1
Świetne znalezisko. Ważne pytanie: czy twoje testy porównawcze uwzględniają dodatkowe operacje, które musiałbyś wykonać find().limit(1)w trakcie normalnego programowania (np. Pobieranie danych i zamykanie kursora), które findOne()i tak robią automatycznie?
Nick Chammas,

@Nick: Myślę, że dodatkowe operacje zostały objęte. Znalazłem przypadkowy dokument ( cookbook.mongodb.org/patterns/random-attribute ), pobrałem dokument za pomocą .next () i usunąłem go z kolekcji. Nie
zamknąłem

@Leftium to muszę zapytać, czy szybciej jest znaleźć find.limit (1), a następnie uzyskać wartość cursur, czy też szybciej jest zrobić findone ()
WojonsTech

2
@WojonsTech: szybki test porównawczy w JS pokazuje findOne () jest faktycznie szybszy. Wyniki mogą się jednak różnić w zależności od sterownika / platformy. Na przykład nie mogłem odtworzyć rzędu różnicy prędkości rzędu JS, który zaobserwowałem pierwotnie ze sterownikiem Java.
Leftium

2
Leftium, zredagowałbym twoją odpowiedź, aby podkreślić, że kiedy faktycznie pobierasz dokument (co normalnie byś zrobił), obie funkcje są w rzeczywistości identyczne, tak jak stwierdza dokumentacja. W tej chwili ktoś prawdopodobnie przeczyta pogrubioną linię na początku twojej odpowiedzi i stwierdzi, że jeśli chce odzyskać jeden dokument, findOne()jest gorszy niż find().limit(1), co jest niepoprawne.
Nick Chammas

5

findOne()jest rzeczywiście cukier syntaktyczny dla find().limit(1), biorąc pod uwagę, że jesteś rzeczywiście pobierania dokumentu (w przeciwieństwie do po prostu powrocie z kursorem find()).

Zobacz odpowiedź i aktualizacje Leftium, aby uzyskać więcej szczegółów.


ok, dziękuję, nie lubię używać funkcji synimus w moim programowaniu, wolę sam ustawić limit jeden, aby cały mój kod był łatwy do wyśledzenia.
WojonsTech,

1
Właściwie w testach porównawczych findOne () jest nieco szybszy niż find (). Limit (1).
Vladimir

@ DairT'arg - Jeśli masz źródła lub dane, aby wykonać kopię zapasową tego roszczenia, zdecydowanie opublikuj odpowiedź ze szczegółami! Z tego, co do tej pory zebrałem, powinny być identyczne, o ile w obu przypadkach pobierasz dokument.
Nick Chammas,

3

Kod źródłowy może bardzo pomóc.

To java, ale myślę, że to też może pomóc.

findOne(),

DBObject findOne(DBObject o, DBObject fields, DBObject orderBy, ReadPreference readPref,
                 long maxTime, TimeUnit maxTimeUnit) {

    QueryOpBuilder queryOpBuilder = new QueryOpBuilder().addQuery(o).addOrderBy(orderBy)
                                                        .addMaxTimeMS(MILLISECONDS.convert(maxTime, maxTimeUnit));

    if (getDB().getMongo().isMongosConnection()) {
        queryOpBuilder.addReadPreference(readPref);
    }

    Iterator<DBObject> i = find(queryOpBuilder.get(), fields, 0, -1, 0, getOptions(), readPref, getDecoder());

    DBObject obj = (i.hasNext() ? i.next() : null);
    if ( obj != null && ( fields != null && fields.keySet().size() > 0 ) ){
        obj.markAsPartialObject();
    }
    return obj;
}

I oto jest find()

public DBCursor find( DBObject ref ){
    return new DBCursor( this, ref, null, getReadPreference());
}

Jak widzimy, że findOne()połączenia find()w to samo, dostaje wszystkie DBOjectw i, a następnie powrót pierwszego.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.