我正在将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",
答案 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秒钟?”。如果是这样,那么您可以将光标移到第二秒的事实就告诉我们问题不在于索引,而是可能与数据量有关被查询读取。
要找出问题发生的位置,您可以收集以下时间:
如果经过的时间为否。 2不超过所经过的时间。 1,那么您就知道问题不在解析中,而更有可能是在网络传输中。如果经过的时间为否。 2比没有大得多。 1,然后您就知道问题出在解析中,您可以深入解析调用以将经过的时间归因于此。它可能是客户端(CPU和/或内存)上的资源受限,或者是次优解析实现。我不能说是删除,但是使用上述方法来找出问题所在的位置至少可以帮助您指导调查。