MongoDB Java驱动程序比带有$ gte / $ lte的控制台要慢得多

时间:2018-09-20 15:57:27

标签: java mongodb performance mongodb-java

我正在将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 :(得分:1)

您正确使用了Java驱动程序,但是您的结论-Java驱动程序比控制台慢得多-是基于无效的比较。这两个代码块是您的问题不等同。在shell变体中,您检索一个游标。在Java变体中,您检索一个光标,然后遍历该光标的内容。

Mongo shell与Java驱动程序之间的有效比较要么必须包括在shell变体中遍历光标,例如:

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,然后您就知道问题出在解析中,您可以深入解析调用以将经过的时间归因于此。它可能是客户端(CPU和/或内存)上的资源受限,或者是次优解析实现。我不能说是删除,但是使用上述方法来找出问题所在的位置至少可以帮助您指导调查。