MongoDB Java驱动程序比使用$gte/$lte的控制台慢得多

MongoDB Java驱动程序比使用$gte/$lte的控制台慢得多,java,mongodb,performance,mongodb-java,Java,Mongodb,Performance,Mongodb Java,我正在使用MongoDB 4.0.1和Java驱动程序(MongoDB驱动程序同步)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")} }) 但如果我用

我正在使用MongoDB 4.0.1和Java驱动程序(MongoDB驱动程序同步)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
    });

您正确地使用了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 
  } 
)
collection.find(
    and(
        eq("c", clientId),
        eq("d", unitId),
        gte("t", start),
        lte("t", end)
        )
    );
或者它必须从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 
  } 
)
collection.find(
    and(
        eq("c", clientId),
        eq("d", unitId),
        gte("t", start),
        lte("t", end)
        )
    );
这两者都是更有效的比较形式。如果您运行其中一个,您将看到经过的时间彼此非常接近。接下来的问题可能是“为什么读取这些数据需要30秒?”。如果是这样的话,您可以在不到一秒的时间内将光标返回,这一事实告诉我们,问题不在于索引,而在于查询读取的数据量

要隔离问题发生的位置,您可以收集以下各项的弹性时间:

  • 读取数据,迭代每个文档,但不要解析每个文档
  • 阅读数据并在阅读时解析每个文档

  • 如果2号的运行时间不超过1号的运行时间,那么您知道问题不在解析中,更可能在网络传输中。如果no.2的运行时间比no.1大得多,那么您知道问题在解析中,您可以深入分析解析调用以确定运行时间的属性。它可能是客户机上受限的资源(CPU和/或内存)或次优解析实现。我现在还不清楚,但使用上述方法来隔离问题所在的位置至少可以帮助您指导调查。

    您是否尝试过使用
    db.setLogLevel(1)
    在MongoDB端记录执行时间?我猜你是在比较苹果和梨,因为Java驱动程序会进行反序列化,这通常是非常昂贵的。也许我不能正确地阅读日志,但它没有给我任何线索,或者时间。我把它贴在主贴子上。就像最后的第一行一样,通常应该有毫秒来告诉你一个操作需要多长时间。我敢打赌,当通过Java或其他任何程序运行它时,您会看到相同的数字。这将证明您所经历的缓慢来自其他地方。有没有更好的方法用Java检索数据?我粘贴的块是整个缓慢的代码。根据您希望在循环中执行的操作,您可以使用投影来限制返回的字段数,从而减少反序列化工作。是否有其他方法来解析数据?我使用了投影的建议,这大大减少了处理时间,但仍然很慢。结果计数在600到700000个文档之间,使用投影将字段减少到5个。任何提示或窍门都会很棒,谢谢!我在答案中添加了一些建议,
    集合。查找(…)
    获取游标,但不读取数据和
    collection.find(…).forEach((块)文档->{//nothing here})
    获取光标并读取数据,但不分析每个文档。是否确定如果forEach块为空,则不分析数据?我认为该文档是准备好的,经过分析的BSON数据?至于时间,在预测之后,1。运行约9.5-10秒2秒。对于10.7,我认为这取决于你所说的“解析”是什么意思。我假设您的意思是“将文档转换为我自己的类型”,但可能您的意思是“序列化数据以传输到客户端,然后在客户端将其反序列化为文档”。