假设我有一个MongoDB集合,其中包含以下文档:
{ "_id": ObjectId("the_object_id"),
"type": "BLOG_POST",
"state": "IN_PROGRESS",
"createDate":ISODate("2017-02-15T01:01:01.000Z"),
"users": {
"posted": ["user1", "user2", "user3"],
"favorited": ["user1", "user4", "user5", "user6"],
"other_fields": "other data",
},
"many_more_fields": "a bunch of other data"
}
我有这样的查询:
db.collection.find({"$and":[
{"type": "BLOG_POST"},
{"$or": [ {"users.posted":"userX"}, {"users.favorited":"userX"} ] },
{"state": {"$ne":"COMPLETED"}}
]}).sort({"createDate":1})
该集合目前只在_id字段中包含索引,并且此查询或示例中未包含某些字段。
就基数而言,文件包括: type = BLOG_POST约占集合的75%,状态$ ne“COMPLETED”约占集合的50%,用户位于users.posted或users.favorited最多2%的集合。
此用例的最佳索引或索引集是什么?
据我了解,我们无法在同一索引中索引users.posted和users.favorited,因为它们都是数组。将来我们可以创建一个新的users.userswhocare数组,它是两个字段的集合,但假设我们不能在短期内进行这种更改。
我还认为$ ne on state意味着通常不会使用状态索引。查询规划器是否能够在索引末尾的state字段中处理$ ne条件?
我想到了一个索引{“type”:1,“createDate”:1,“state”:1},这样查询就会遇到类型,使用createDate进行排序,并处理$ ne与索引的最后一位。它仍然需要拿起35%-40%的文档来测试用户。不好,但比目前的收集扫描有所改进。
或者我可以创建两个索引,一个像{“users.posted”:1,“type”:1,“createDate”:1,“state”:1}和{“users.favorited”:1,“输入“:1,”createDate“:1,”state“:1}。 查询规划器是否会使用这两个索引的交集来更快地找到感兴趣的文档?
我们目前正在使用MongoDB 3.2.5。如果MongoDB 3.2和3.4之间的答案存在差异,我很想知道它们。
答案 0 :(得分:0)
经过一些分析,我发现添加多个查询users.posted
和users.favorited
作为相应索引中的第一项都表现得更好,并由MongoDB查询计划器选择。
我创建了索引:
db.collection.createIndex({"users.posted":1, "type":1, "createDate":1, "state":1})
db.collection.createIndex({"users.favorited":1, "type":1, "createDate":1, "state":1})
由于users.posted和users.favorited的基数很高(任何一个将包含不超过集合的2%,大部分时间小于0.5%),MongoDB查询计划器同时使用索引交集。
我针对索引测试了这个:
db.collection.createIndex({"type":1, "createDate":1, "state":1}).
使用explain()
和explain("executionStats")
查看针对两个查询的解释计划,查询计划程序使用{“$或”:{{“users.posted”:“userX”的索引扫描},{“users.favorited”:“userX”}]}部分查询作为第一阶段。这导致了最少的总检查次数和总检查次数。