Різниця між дзвінками MongoDB та викликами findone


34

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

Відповіді:


33

Виходячи з моїх власних орієнтирів, find().limit(1)на порядок швидше, ніж findOne().

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

оновлення: відповідь інженера 10gen (MongoDB):

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

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


1
Чудова знахідка. Однак важливе питання: Чи враховують ваші орієнтири додаткові операції, які вам доведеться виконати find().limit(1)під час звичайного програмування (наприклад, фактичне отримання даних та закриття курсору), що findOne()автоматично робить для вас все одно?
Nick Chammas

@ Nick: Я думаю, додаткові операції були охоплені. Я знаходив випадковий документ ( cookbook.mongodb.org/patterns/random-attribute ), діставав документ із .next () та вилучав його з колекції. Я не вручну закрив жодні курсори ...
Лефтій

@Leftium, то я повинен запитати, чи швидше зробити find.limit (1), а потім отримати значення cursur чи швидше зробити findone ()
WojonsTech

2
@WojonsTech: швидкий показник у JS показує findOne () насправді швидше. Результати можуть відрізнятися залежно від драйвера / платформи. Наприклад, я не зміг відтворити порядки різниці швидкостей у JS, які спочатку спостерігав з драйвером Java.
Лефтій

2
Лефтій, я би відредагував вашу відповідь, наголосивши, що коли ви фактично отримуєте документ (який, як правило, виконувались), ці дві функції насправді однакові, як і в документації. Зараз хтось, ймовірно, прочитає жирний шрифт на початку вашої відповіді і зробить висновок, що якщо вони хочуть отримати один документ, findOne()це гірше ніж find().limit(1), що невірно.
Нік Шамма

5

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

Дивіться відповідь та оновлення Leftium для отримання більш детальної інформації.


гаразд, дякую, я не люблю використовувати функції синімусу в моєму програмуванні, швидше за все, обмежую себе, так що весь мій код легко знайти.
WojonsTech

1
Насправді в орієнтирах findOne () трохи швидше, ніж find (). Limit (1).
Володимир

@ DairT'arg - Якщо у вас є джерела чи дані для резервного копіювання цієї претензії, обов'язково опублікуйте відповідь із деталями! З того, що я зібрав до цих пір, вони повинні бути ідентичними, якщо ви отримуєте документ в обох випадках.
Нік Чаммас

3

Вихідний код може дуже допомогти.

Це Java, але, мабуть, теж може допомогти.

The 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і потім повертають перший.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.