我已经在SO上浏览了近10篇类似的帖子,但我仍然对我得到的结果感到困惑:在42K文档集合和19条记录集合之间的单个$查找聚合上,在外部字段上进行排序需要5秒。也就是798K的总向量积。
不幸的是,在这里,非规范化不是一个很好的选择,因为“to”集合中的文档被大量共享,并且在进行更改时需要在整个数据库中进行大量更新。
话虽如此,我似乎不明白为什么接下来要花这么长时间。我觉得我一定做错了什么。
上下文:
>
一个4 vCPU、16 GB RAM VM作为单个节点副本集运行Debian 10/MongoDB 4.4,仅此而已。完全更新。NET MongoDB驱动程序(我刚刚更新并重新测试)
聚合中有一个查找,“from”集合有42K个文档,“to”集合有19个文档。
所有聚合、索引和集合都使用默认排序规则。
“to”集合中的外部字段具有索引。是的,只是为了那19张唱片,以防万一会有所不同。
其中一篇关于慢速$查找性能的帖子提到,如果$查找阶段的嵌套管道中没有使用$eq,它将不会使用索引。因此,我确保聚合管道使用$eq操作符。
管道是这样的:
[{ "$lookup" :
{ "from" : "4",
"let" : { "key" : "$1" },
"pipeline" :
[{ "$match" :
{ "$expr" :
{ "$eq" : ["$id", { "$substrCP" : ["$$key", 0, { "$indexOfCP" : ["$$key", "_"] }] }] } } },
{ "$unwind" : { "path" : "$RF2" } },
{ "$match" : { "$expr" : { "$eq" : ["$RF2.id", "$$key"] } } },
{ "$replaceRoot" : { "newRoot" : "$RF2" } }],
"as" : "L1" } },
{ "$sort" : { "L1.5" : 1 } },
{ "$project" : { "L1" : 0 } },
{ "$limit" : 100 }]
去掉嵌套的$unwind/$match/$replaceRoot组合会占用大约30%的运行时间,将其缩短到3.5秒,但是,这些阶段对于链接/查找到适当的子文档是必要的。在0.5秒内对“from”集合进行排序,无需查找。
我做错了什么?提前感谢!
编辑:
我刚刚用一组更大的记录测试了同样的事情(“from”集合中的38K记录,“to”集合中的26K记录,一对一的关系)。完成排序花了7分钟以上。我在Compass中检查并看到“id”上的索引实际上正在使用(在7分钟内不断刷新并看到它上升,我目前是数据库的唯一用户)。
这是一条比第一条更简单的管道:
[{ "$lookup" :
{ "from" : "1007",
"let" : { "key" : "$13" },
"pipeline" :
[{ "$match" :
{ "$expr" : { "$eq" : ["$id", "$$key"] } } }],
"as" : "L1" } },
{ "$sort" : { "L1.1" : -1 } },
{ "$project" : { "L1" : 0 } },
{ "$limit" : 100 }]
考虑到上述信息,7分钟听起来合理吗?
编辑2:
shell代码创建两个40k记录集合(prod和prod2),两个字段(name: string, uid: integer):
var randomName = function() {
return (Math.random()+1).toString(36).substring(2);
}
for (var i = 1; i <= 40000; ++i) {
db.test.insert({
name: randomName(),
uid: i });
}
我在prod2的“uid”字段上创建了一个索引,将Compass的示例文档限制增加到50k,然后只进行了以下查找,这花费了整整两分钟的时间进行计算:
{ from: 'prod2',
localField: 'uid',
foreignField: 'uid',
as: 'test' }
编辑3:
我刚刚还直接从shell运行了聚合管道,并在几秒钟内而不是两分钟内获得了结果:
db.test1.aggregate([{ $lookup:
{ from: 'test2',
localField: 'uid',
foreignField: 'uid',
as: 'test' } }]).toArray()
是什么导致炮弹和指南针以及。网络驱动程序?
对于任何无意中读到这篇文章的人来说,以下内容对我很有用:使用$lookup操作符的localField/foreignField版本。
在Compass中监视索引时,let/管道和localField/外国字段版本都达到了适当的索引,但在使用let/管道版本时速度慢了几个数量级。
我重新构造了查询构建逻辑,只使用localField/foreignField,这带来了很大的不同。
问题内容: 我有一些复杂的对象,例如猫,它具有许多属性,例如年龄,喜爱的猫食等等。 Java集中存储了一堆猫,我需要查找所有3岁的猫,或者最喜欢猫粮的Whiskas。当然,我可以编写一个自定义方法来查找那些具有特定属性的Cat,但是这样做会麻烦许多属性。有一些通用的方法吗? 问题答案: 您可以编写一个采用接口实例的方法,该实例定义了一个方法,该方法可以通过所需的任何属性检查来实现。 更好的是,使其
我有一个排序的值数组和一个值,如下所示: 我可以找到在保持排序顺序的同时将插入到中的值的索引: 代码很好而且紧凑,但我有一种直觉,在幕后这是非常低效的:因为不知道数组已排序,所以它必须检查所有值。 有没有更好的方法找到这个指数值? 注意:我对实际合并到不感兴趣,我只想要索引值。
我有一个包含元素列表的实体,现在我想搜索这些元素的属性。这个约束应该是“与”连接的。请看这些简单的例子: 现在我想找到某个城市的家长,比如说“BigCity”,孩子们在学校“AwesomeSchool”,他们在六年级一班。我只想通过CriteriaBuilder获得搜索结果。 到目前为止,我得到了: 不幸的是,这里有两个问题:-看起来我无法在列表属性上调用-这将返回所有孩子在“AwesomeSch
我有两个收藏品 员额:
假设我有三个指数:城市、博物馆和景点。 现在我正在查询一个术语的所有索引(),例如“维也纳” 作为结果,我得到: 维也纳:维也纳艺术博物馆 有没有办法优先考虑指数,这样我就可以得到第一个城市,而不是景点,最后是博物馆,就像这样: 维也纳 维也纳的Riesenrad 维也纳:维也纳艺术博物馆 维也纳:维也纳历史博物馆
问题内容: 我需要计算出 仅 在python中所有可能的 大小写 排列的列表,例如,使用ar输入它将返回[‘ar’,’Ar’,’aR’,’AR’] 或arc [‘arc’,’ Arc”,“ ARc”,“ aRc”,“ aRC”,“ ARC”],我知道可能有一些不错的方法,但对于我的一生,我无法弄清楚。 问题答案: