1.但是我想知道,当我们在 'a'&'b' 上创建联合索引时,它与简单索引的工作方式有何不同?
MongoDB 每个查询只使用一个索引.. 所以如果您的find() 条件同时包含a 和b 值,您应该添加一个复合索引来有效地搜索这两个字段。
2.为什么我们只找到'a'会受益,但如果找到'b',我们不会从中受益?联合索引是否像 concatenate 'a'&'b' 这样我们就可以从 Prefix 中受益?
MongoDB 使用B-tree indexes,因此您只能使用前缀有效地匹配部分键。要查找与后缀或子字符串匹配的所有可能值,必须检查所有索引条目。
设置测试数据进行比较
以下示例使用mongo shell:
/* Generate some test data */
for (i = 0; i< 1000; i++) {
db.mycoll.insert({a:i})
db.mycoll.insert({b:i})
db.mycoll.insert({a:i,b:i})
}
现在添加一些示例索引:
/* Add simple and compound index */
db.mycoll.ensureIndex({a:1})
db.mycoll.ensureIndex({b:1})
db.mycoll.ensureIndex({a:1, b:1})
最后,对于下面的测试场景,强制您的查询使用带有$hint 的特定索引并比较explain() 的结果。
使用简单索引搜索b
使用b 上的简单索引搜索b 可以直接在索引中找到匹配的条目。它会扫描4 个索引条目(nscanned)以返回4 个结果(n):
db.mycoll.find({b:10}).hint({b:1}).explain()
{
"cursor" : "BtreeCursor b_1",
"n" : 4,
"nscannedObjects" : 4,
"nscanned" : 4,
...
}
使用复合索引(a,b) 搜索b
使用(a,b) 上的复合索引搜索b 必须检查索引中的每个a 值,因为索引的第一部分是a 的键值。
所以要直接在索引中查找匹配条目.. 它会扫描 1904 个索引条目 (nscanned) 以返回 4 个结果 (n):
db.mycoll.find({b:10}).hint({a:1,b:1}).explain()
{
"cursor" : "BtreeCursor a_1_b_1",
"n" : 4,
"nscannedObjects" : 4,
"nscanned" : 1904,
...
}
从技术上讲,扫描 1,904 个文档少于我的测试集合中的 3,000 个文档。但这远非最佳。
使用复合索引(a,b) 搜索a
为了比较,使用复合索引搜索a表明只需要扫描4个值即可返回4个文档:
db.mycoll.find({a:10}).hint({a:1,b:1}).explain()
{
"cursor" : "BtreeCursor a_1_b_1",
"n" : 4,
"nscannedObjects" : 4,
"nscanned" : 4,
"nscannedObjectsAllPlans" : 4,
...
}
更多示例和解释,我建议阅读文章Optimizing MongoDB Compound Indexes。