情况:
我有100万用户,我想通过标签搜索它们。
以下是架构:
const Account = new Schema({
tags: { type: [String], default: ['cats'] }
})
这是第一个查询:
const query = { tags: 'cats'}
const fields = { _id: 0 }
const options = { skip: 0, limit: 5 }
Account.find(query, fields, options)
调用find
方法Mongoose
后,将开始搜索并返回它匹配的前5个条目。在这种情况下的表现是最佳的。
这是第二个查询:
const query = { tags: 'cats'}
const fields = { _id: 0 }
const options = { skip: 500 000, limit: 5 }
Account.find(query, fields, options)
在这种情况下发生的事情对我很感兴趣。
Mongoose
首先匹配500 000个条目然后返回接下来的5个条目吗?
或者以某种方式跳过'跳跃'到500 000元素而不必事先将它们全部匹配?
我试图了解这个过程的效率如何以及我是否可以某种方式改进它。你有什么建议吗?
答案 0 :(得分:2)
有趣。我的理解是Find
这里的查询功能与Select
非常相似,其中在跳过它们之前首先通过500,000个值会效率低下。
因此,我建议实现一种称为多级索引的东西。基本上创建嵌套索引系统虽然占用数据空间,但非常有效,特别是对于您不希望直接实现树的顺序搜索实践。在移动到存储的数据块之前,创建一组更通用的外部索引,然后分别将它们链接到内部索引。
实现这一点应该不会太困难,并且应该大大改善遍历的数量。希望这会有所帮助。
答案 1 :(得分:2)
是的,它首先匹配500,000个条目。
来自MongoDB权威指南第2版:
$ skip接受一个数字n,并从结果集中丢弃前n个文档。与“普通”查询一样,对于大型跳过效率不高,因为它必须找到必须跳过的所有匹配项,然后将其丢弃。
您可以使用explain():
从Mongo shell详细检查您的查询https://docs.mongodb.com/manual/reference/method/cursor.explain/
例如:
// Create a dummy collection
var tagTypes = ['cats', 'dogs', 'chickens']
for (i=0; i < 1000; i++) {
let tag = tagTypes[Math.floor(Math.random()*tagTypes.length)]
db.people.insert({"tags" : [tag]})
}
然后解释一下
db.people.find({"tags" : "cats"}).skip(100).limit(10).explain("executionStats”)
totalDocsExamined向您显示它正在匹配正在跳过的所有内容
"executionStats" : {
...
"totalDocsExamined" : 420
如果要在标签上创建索引:
db.people.ensureIndex({ "tags" : 1 })
再次运行它你会得到:
"executionStats" : {
...
"totalDocsExamined" : 110