Разница между поиском MongoDB и вызовами findone

34

Я работаю над проектом, и я не уверен, есть ли разница между тем, как findработает курсор и как findOneработает курсор. FindOne - просто обертка для find().limit(1)? Я искал это и, возможно, кто-то знает, есть ли у mongodb специальный метод для этого или нет. Я работаю с PHP API для mongodb, если это имеет значение.

WojonsTech
источник

Ответы:

33

Исходя из моих собственных тестов, find().limit(1)это на порядки быстрее, чем findOne().

Существует либо ошибка в документации MongoDB, либо ошибка в findOne(). findOne()больше похоже на то, find().limit(N)где N - количество документов, которое должен вернуть запрос. Я понял это, пытаясь понять, почему мои простые запросы были такими медленными!

обновление: ответ от инженера 10gen (MongoDB):

Два запроса, которые вы выполняете, очень разные. Запрос на поиск возвращает курсор, это по сути сценарий без операций, так как никакие фактические данные не возвращаются (только информация о курсоре). Если вы вызываете findOne, то вы фактически возвращаете данные и закрываете курсор. Документы определенно должны быть понятнее :-)

Обновление: действительно, если find().limit(1)документ извлекается, разница в скорости на порядки кажется исчезающей. Кроме того, я не смог воспроизвести существенную разницу в скорости с драйвером MongoDB JavaScript. Первоначально я тестировал с помощью драйвера MongoDB Java.

Leftium
источник
1
Отличная находка. Важный вопрос, однако: учитывают ли ваши тесты дополнительные операции, с которыми вам придется иметь дело find().limit(1)в ходе обычного программирования (например, на самом деле извлечение данных и закрытие курсора), которое findOne()в любом случае автоматически делает для вас?
Ник Чаммас
@ Ник: Я думаю, что дополнительные операции были покрыты. Я находил случайный документ ( cookbook.mongodb.org/patterns/random-attribute ), получал документ с помощью .next () и удалял его из коллекции. Я не закрывал вручную никаких курсоров ...
Leftium
@Leftium, тогда я должен спросить, быстрее ли сделать find.limit (1) и затем получить значение cursur, или быстрее найти findone ()
WojonsTech
2
@WojonsTech: быстрый тест в JS показывает, что findOne () на самом деле быстрее. Результаты могут отличаться в зависимости от водителя / платформы. Например, я не смог воспроизвести разницу скорости порядка в JS, которую я первоначально наблюдал с драйвером Java.
Leftium
2
Leftium, я бы отредактировал ваш ответ, подчеркнув, что когда вы на самом деле получаете документ (что вы обычно делаете), две функции фактически идентичны, как указано в документации. Прямо сейчас кто-то, скорее всего, прочтет жирную строку в начале вашего ответа и решит, что если он хочет получить один документ, findOne()это хуже, чем find().limit(1)неверно.
Ник Чаммас
5

findOne()действительно синтаксический сахар для find().limit(1), учитывая, что вы на самом деле извлекаете документ (в отличие от простого возврата курсора с помощью find()).

Смотрите ответ и обновления Leftium для более подробной информации.

Ник Чаммас
источник
хорошо, спасибо, я не люблю использовать в своем программировании функции synimus, я бы предпочел сам ограничить их, чтобы весь мой код легко отслеживать.
WojonsTech
1
На самом деле в тестах findOne () немного быстрее, чем find (). Limit (1).
Владимир
@ DairT'arg - Если у вас есть источники или данные, подтверждающие эту претензию, обязательно опубликуйте ответ с подробностями! Из того, что я до сих пор собирал, они должны быть идентичными, если вы извлекаете документ в обоих случаях.
Ник Чаммас
3

Исходный код может сильно помочь.

Это Java, но я думаю, это тоже может помочь.

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;
}

И вот find()

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

Как мы можем видеть , что findOne()вызовы find()в нем себя, получает все DBOjectв iи затем возвращают первый.

shellbye
источник