我正在使用 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 秒?”。如果是这样,您可以在亚秒内让光标返回的事实告诉我们,问题与索引无关,而可能与数据量有关正在被查询读取。
要确定问题发生的位置,您可以收集以下内容的耗时:
- 读取数据,迭代每个文档,但不解析每个文档
- 读取数据并在读取的同时解析每个文档
如果没有耗时。 2 并不比 1 号的耗时多多少。 1 那么你就知道问题不在于解析,而更可能在于网络传输。如果没有耗时。 2比没有大得多。 1 那么您就知道问题出在解析中,您可以深入分析解析调用以归因所耗时。它可能是客户端资源有限(CPU 和/或内存)或次优解析实现。我无法判断是否已删除,但使用上述方法来隔离问题所在至少可以帮助您指导调查。
关于java - MongoDB Java 驱动程序比带有 $gte/$lte 的控制台慢得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52428997/