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

标签 java mongodb performance mongodb-java

我正在使用 MongoDB 4.0.1 和 Java 驱动程序 (MongoDB-driver-sync) 3.8.0

我的集合有 564'039 个元素,具有 13 个键值,其中 2 个是具有 10 个以上键值的 map 。

如果我在控制台中执行以下查询,它会在不到一秒的时间内给出结果:

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", 

最佳答案

您正确使用了 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 号的耗时多多少。 1 那么你就知道问题不在于解析,而更可能在于网络传输。如果没有耗时。 2比没有大得多。 1 那么您就知道问题出在解析中,您可以深入分析解析调用以归因所耗时。它可能是客户端资源有限(CPU 和/或内存)或次优解析实现。我无法判断是否已删除,但使用上述方法来隔离问题所在至少可以帮助您指导调查。

关于java - MongoDB Java 驱动程序比带有 $gte/$lte 的控制台慢得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52428997/

相关文章:

mongodb - 使用 Docker 安装旧版本的 MongoDB

python - numpy/scipy 中牛顿力的最高效计算

java - @Transactional 大大减慢了 Rest API

java - 在字符串中查找日期

java - Java VM 是否移动内存中的对象,如果是,如何移动?

javascript - 被推送到数组的缓存选择器

c++ - Valgrind 是否有像 Purify/Quantify 这样的 API 可以让你禁用数据记录?

java - 内存泄漏或者是预料之中的

mongodb - "This node was not started with the replSet option"

mongodb - 如何在 MongoDB 中使用一个查询更新多个文档