我最近不得不优化我们 MongoDB 上的某些查询集,并遇到了这个特殊问题:
假设我有一个匹配 A 和 B 的查询,然后在 C 上进行范围选择,并通过在 上排序输出code>D,所以在 shell 中它们看起来像:
db.collection.find({ A: 'something', B: 'something-else', C: { $gt: 100 } })
.sort({ D: -1 }).limit(10)
我read a post去年谈到为这种场景创建索引,他们的基本规则:
他们的树解释看起来很合理,所以我继续创建了一个索引:
db.collection.ensureIndex({ A:1, B:1, D:-1, C:-1 })
现在问题来了:mongodb 认为 BasicCursor 比这个索引更好。如果我提示完整的索引,它就可以工作(而且速度更快),但这样做需要对我们的代码库进行相当多的更改,因此我们正在尽可能避免这种情况。
我的问题是:
为什么 mongodb 查询优化器决定 { A:1, E:-1 }, { D:-1 } 甚至 BasicCursor 比 { A:1, B:1, D:-1, C:-1 },当我的查询包含所有 4 个字段时。
{ A:1, D:-1 } 是否冗余,mongo docs是否说使用部分索引效率较低?
此外,我们还有如下查询:
db.collection.find({ A: { $in : ['str1','str2'] }, B: 'something', C: { $gt: 100 } })
.sort({ D: -1 }).limit(10)
为了高效查询,我们是否需要像下面这样的额外索引?坦率地说,我不确定 MongoDB 查询优化器将如何处理它们。
db.collection.ensureIndex({ B:1, D:-1, C:-1, A:1 })
这些是我的查询的解释,有提示和没有提示。
原来它默认为 { A:1, E:-1 } 而不是 { A:1, D:-1 } ,这看起来更奇怪我们没有查询字段 E。
我在 { A:1, E:-1 } 上删除了索引,现在解释告诉我它默认为 { D:-1 },所以我删除了它也是,现在 MongoDB 开始使用 BasicCursor... 它似乎既不喜欢我的完整索引也不喜欢 A:1, D:-1 索引(尽管提示会带来更好的性能)。
这感觉很奇怪。
最佳答案
发生这种“不寻常”的唯一原因是,如果您的数据分布恰好是 BasicCursor 实际上比索引查询更快地完成查询(即找到所有匹配的文档)。 “部分”索引也是如此。
以您的数据结构为例,如果 a 在集合的开头具有相对较少的不同值,并且 b 具有极低的基数(即非常少的不同值,例如 one 或 a少数)然后按顺序扫描集合或使用“效率较低”的索引将显示与使用理论上的“理想”索引相同或更好的性能。
这是一个示例,其中前 1000 个文档具有 a=1 和 b=2 - 后面的文档分布非常不同。
> db.compound4.find({a:1, b:2, d:{$lt:100}}).sort({c:-1}).limit(10).explain(true)
{
"cursor" : "BtreeCursor a_1",
"isMultiKey" : false,
"n" : 10,
"nscannedObjects" : 18,
"nscanned" : 18,
"nscannedObjectsAllPlans" : 46,
"nscannedAllPlans" : 56,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"a" : [
[
1,
1
]
]
},
"allPlans" : [
{
"cursor" : "BtreeCursor a_1",
"n" : 18,
"nscannedObjects" : 18,
"nscanned" : 18,
"indexBounds" : {
"a" : [
[
1,
1
]
]
}
},
{
"cursor" : "BtreeCursor a_1_b_1_c_1_d_1 reverse",
"n" : 10,
"nscannedObjects" : 10,
"nscanned" : 20,
"indexBounds" : {
"a" : [
[
1,
1
]
],
"b" : [
[
2,
2
]
],
"c" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"d" : [
[
100,
-1.7976931348623157e+308
]
]
}
},
{
"cursor" : "BasicCursor",
"n" : 18,
"nscannedObjects" : 18,
"nscanned" : 18,
"indexBounds" : {
}
}
]
}
由于复合索引很大,它比较小的部分索引需要更长的时间来遍历,并且由于“b”的选择性不是很好(即非常差),这使得查询计划落后。
关于php - MongoDB:复合索引决策,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20828977/
我发现自己需要这个。假设cart是一个包含用户列表的模型。defindex_of_itemcart.users.each_with_indexdo|u,i|ifu==current_userreturniendend获取此类关联索引的更简单方法是什么? 最佳答案 indexArray上的方法与您的index_of_item方法相同,例如cart.users.index(current_user)返回数组中第一个对象的索引==给obj。如果未找到匹配项,则返回nil。 关于ruby-on-
因此,当我遵循MichaelHartl的RubyonRails教程时,我注意到在用户表中,我们为:email属性添加了一个唯一索引,以提高find的效率方法,因此它不会逐行搜索。到目前为止,我们一直在根据情况使用find_by_email和find_by_id进行搜索。然而,我们从未为:id属性设置索引。:id是否自动索引,因为它在默认情况下是唯一的并且本质上是顺序的?或者情况并非如此,我应该为:id搜索添加索引吗? 最佳答案 大多数数据库(包括sqlite,这是RoR中的默认数据库)会自动索引主键,对于RailsMigration
假设我有一个可枚举对象enum,现在我想获取第三个项目。我知道一种通用方法是转换成数组,然后使用索引访问,如:enum.to_a[2]但这种方式会创建一个临时数组,效率可能很低。现在我使用:enum.each_with_index{|v,i|breakvifi==2}但这非常丑陋和多余。执行此操作最有效的方法是什么? 最佳答案 你可以使用take剥离前三个元素,然后剥离last从take给你的数组中获取第三个元素:third=enum.take(3).last如果您根本不想生成任何数组,那么也许:#Ifenumisn'tanEnum
在我的场景中,Logstash收到的系统日志行的“时间戳”是UTC,我们在Elasticsearch输出中使用事件“时间戳”:output{elasticsearch{embedded=>falsehost=>localhostport=>9200protocol=>httpcluster=>'elasticsearch'index=>"syslog-%{+YYYY.MM.dd}"}}我的问题是,在UTC午夜,Logstash在外时区(GMT-4=>America/Montreal)结束前将日志发送到不同的索引,并且索引在20小时(晚上8点)之后没有日志,因为“时间戳”是UTC。我们已
我想从特定索引开始遍历数组。我该怎么做?myj.eachdo|temp|...end 最佳答案 执行以下操作:your_array[your_index..-1].eachdo|temp|###end 关于ruby-从特定索引开始迭代数组,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/44151758/
我一直在努力学习如何处理由数组组成的数组。假设我有这个数组:my_array=[['ORANGE',1],['APPLE',2],['PEACH',3]我将如何找到包含'apple'的my_array索引并删除该索引(删除子数组['APPLE',2]因为'apple'包含在该索引的数组中)?谢谢-我非常感谢这里的帮助。 最佳答案 您可以使用Array.select过滤掉项目:>>a=[['ORANGE',1],['APPLE',2],['PEACH',3]]=>[["ORANGE",1],["APPLE",2],["PEACH",3
我想使用部分字符串搜索数组,然后获取找到该字符串的索引。例如:a=["Thisisline1","Wehaveline2here","andfinallyline3","potato"]a.index("potato")#thisreturns3a.index("Wehave")#thisreturnsnil使用a.grep将返回完整的字符串,使用a.any?将返回正确的true/false语句,但都不会返回匹配的索引找到了,或者至少我不知道该怎么做。我正在编写一段代码,该代码读取文件、查找特定header,然后返回该header的索引,以便它可以将其用作future搜索的偏移量。如果
如何在rakedb:migrate:status中删除带有“**NOFILE**”的迁移ID列表?例如:StatusMigrationIDMigrationName--------------------------------------------------up20131017204224Createusersup20131218005823**********NOFILE**********up20131218011334**********NOFILE**********我不明白为什么当我自己手动删除它时它仍然保留旧的迁移文件,因为我正在研究迁移的工作原理。这是为了记录吗?但
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它
假设我有这个:[{:id=>34,:votes_count=>3},{:id=>2,:votes_count=>0},]如何根据id获取索引?我想要做的是在搜索id:34时返回0,在搜索id:21/。什么是最有效的方法? 最佳答案 你可以将一个block传递给#index:array.index{|h|h[:id]==34}#=>0 关于ruby-根据子哈希值获取数组索引,我们在StackOverflow上找到一个类似的问题: https://stackove