// about 300 hundred ids at a time (i've tried lower and higher numbers - no impact
db.users.find({_id : {$in : [1,2,3,4,5,6....]}})
一旦我得到光标,我会做:cursor.toArray()
,然后迭代结果
toArray操作非常慢。他们平均需要大约一分钟。重要提示:我的数据库始终处于非常繁重的负载状态。这个特殊的系列有超过50毫米的条目。
我已将mongo java驱动程序中的问题缩小到com.mongodb.Response - 特别是这一行:
final byte [] b = new byte[36];
Bits.readFully(in, b);
令人难以置信的只有36个字节的读取有时需要一分钟!
当我为数据库带来负担时,改进非常激烈。从大约一分钟到5-6秒。我的意思是5-6秒获得300个文件仍然超级慢,但肯定比1分钟更好。
我可以做些什么来进一步解决这个问题?我需要查看MondoDB上的设置吗?
答案 0 :(得分:0)
您正在加载所有300个用户文档。
搜索_id
索引并将相应文档完全发送到您的应用程序会发生什么。因此,mongoDB将访问它的数据文件,读取第一个文档并将其发送给您,然后它跳转到下一个文档并将其发送给您,依此类推。如果您使用了游标,只要返回了大量等于您定义的游标大小的文档,您就可以开始迭代返回的文档,因为其他文档将根据需要从服务器上的游标延迟加载。 (有点简化,但足以回答这个问题)。你要做的是明确地等待,直到扫描索引,找到文档,发送回你的应用程序并将其到达最后一个文档的最后一个字节。正如@wdberkeley(为10gen工作)正确地指出,这是一个非常糟糕的想法。
在重负荷下,可能会发生两件事。您的_id
索引不再存在于RAM中的可能性更大,导致数千(如果不是数百万)从磁盘读取 - 这是慢。比索引保存在RAM中要快得多(几个数量级)。所以它不是你提到的代码片段,而是MongoDB的响应时间导致延迟。重负载下的另一个选择是您的磁盘IO太低或(更有可能)随机文件读取延迟太高。我假设您正在使用旋转磁盘加上没有足够的RAM来存放大小的数据库。
db.users.stats()
查找索引大小。我很确定你的索引大小(合并)超过你的可用内存。如果没有足够的RAM,可以放大或缩小。
如果您的磁盘延迟或吞吐量太高,要么横向扩展,要么(在大多数情况下更好,更便宜)使用SSD来存储MongoDB的数据。
使用游标对象迭代文档。在我能想到的几乎所有用例中,这是一个更好的解决方案。
答案 1 :(得分:0)
将MongoDB驱动程序升级到3.6.4将立即获取数据。 我们的收藏集中有大约200万份文档,而以前的版本大约需要3分钟的时间,但是升级到3.6.4后仅花费了5-7秒的时间。所以我觉得旧版本存在一些问题的mongoDB驱动程序。