Java-драйвер MongoDB намного медленнее, чем консоль с $ gte / $ lte - PullRequest
0 голосов
/ 20 сентября 2018

Я использую MongoDB 4.0.1 с драйвером Java (MongoDB-driver-sync) 3.8.0

В моей коллекции 564'039 элементов с 13 значениями ключей, 2 из которых являются картами с 10больше значений ключа.

Если я выполню следующий запрос в консоли, он даст мне результаты менее чем за секунду:

db.getCollection('tracking_points').find({c: 8, d: 11,
  t: {$gte: new Date("2018-08-10"), $lte: new Date("2018-09-10")}
})

Но если я выполню это в Java, потребуетсяболее 30 секунд:

collection.find(
    and(
        eq("c", clientId),
        eq("d", unitId),
        gte("t", start),
        lte("t", end)
        )
    ).forEach((Block<Document>) document -> {
        // nothing here
    });

Существует индекс "t" (метка времени), и без него поиск консоли занимает несколько секунд.

Как это можно исправить?

Редактировать: вот журнал из БД после Java-запроса:

"2018-09-21T08:06:38.842+0300 I COMMAND  [conn9236] command fleetman_dev.tracking_points command: count { count: \"tracking_points\", query: {}, $db: \"fleetman_dev\", $readPreference: { mode: \"primaryPreferred\" } } planSummary: COUNT keysExamined:0 docsExamined:0 numYields:0 reslen:45 locks:{ Global: { acquireCount: { r: 1 } }, Database: { acquireCount: { r: 1 } }, Collection: { acquireCount: { r: 1 } } } protocol:op_msg 0ms", 
"2018-09-21T08:06:38.862+0300 I COMMAND  [conn9236] command fleetman_dev.tracking_points command: find { find: \"tracking_points\", filter: { c: 8, d: 11, t: { $gte: new Date(1536526800000), $lte: new Date(1536613200000) } }, $db: \"fleetman_dev\", $readPreference: { mode: \"primaryPreferred\" } } planSummary: IXSCAN { t: 1 } cursorid:38396803834 keysExamined:101 docsExamined:101 numYields:0 nreturned:101 reslen:24954 locks:{ Global: { acquireCount: { r: 1 } }, Database: { acquireCount: { r: 1 } }, Collection: { ", 
"2018-09-21T08:06:39.049+0300 I COMMAND  [conn9236] command fleetman_dev.tracking_points command: getMore { getMore: 38396803834, collection: \"tracking_points\", $db: \"fleetman_dev\", $readPreference: { mode: \"primaryPreferred\" } } originatingCommand: { find: \"tracking_points\", filter: { c: 8, d: 11, t: { $gte: new Date(1536526800000), $lte: new Date(1536613200000) } }, $db: \"fleetman_dev\", $readPreference: { mode: \"primaryPreferred\" } } planSummary: IXSCAN { t: 1 } cursorid:38396803834 keysExamined:33810 doc", 

1 Ответ

0 голосов
/ 21 сентября 2018

Вы используете драйвер Java правильно, но ваш вывод - что драйвер Java намного медленнее, чем консоль, - основан на неверном сравнении.Два кодовых блока вашего вопроса не эквивалентны.В варианте оболочки вы получаете курсор.В варианте Java вы извлекаете курсор и , когда вы перемещаетесь по содержимому этого курсора.

Для правильного сравнения между оболочкой Mongo и драйвером Java может потребоваться обход курсорав варианте оболочки, например:

db.getCollection('tracking_points').find({c: 8, d: 11,
  t: {$gte: new Date("2018-08-10"), $lte: new Date("2018-09-10")}
}).forEach(
  function(myDoc) { 
    // nothing here 
  } 
)

Или пришлось бы убрать ходьбу над курсором из варианта Java, например:

collection.find(
    and(
        eq("c", clientId),
        eq("d", unitId),
        gte("t", start),
        lte("t", end)
        )
    );

Оба они будут болеедействительные формы сравнения.Если вы запустите один из них, вы увидите, что прошедшее время на намного ближе друг к другу.Следующим вопросом может быть «почему для считывания этих данных требуется 30 секунд?».Если это так, то, что вы можете вернуть курсор на доли секунды, говорит нам, что проблема не в индексации , а скорее в том, что она связана с объемом данных , которые читаютсяпо запросу.

Чтобы изолировать, где возникает проблема, вы можете собрать время ожидания для следующего:

  1. читать данные, перебирать каждый документ, но не анализировать каждый документ
  2. читать данные и анализировать каждый документ при чтении

Если истекшее время для нет.2 не намного больше, чем истекшее время для нет.1, то вы знаете, что проблема не в разборе и, скорее всего, в передаче по сети.Если истекшее время для нет.2 намного больше, чем нет.1, тогда вы знаете, что проблема в разборе, и вы можете покопаться в вызове разбора, чтобы определить прошедшее время.Это могут быть ограниченные ресурсы на клиенте (ЦП и / или память) или субоптимальная реализация анализа.Я не могу сказать, как удалить, но использование описанного выше подхода для определения места, где находится проблема, по крайней мере, поможет вам направить ваше расследование.

...