我一直在研究MongoDB上的数组(多键)索引,我有以下问题,但是我找不到很多文档:
子文档数组上的索引
所以,如果我有一个类似于:
的数组字段{field : [
{a : "1"},
{b : "2"},
{c : "3"}
]
}
我仅在field.a
和field.c
单独查询(不是一起查询),我相信我可以选择以下备选方案:
db.Collection.ensureIndex({field : 1});
db.Collection.ensureIndex({field.a : 1});
db.Collection.ensureIndex({field.c : 1});
即:整个数组的索引;或嵌入字段上的两个索引。现在我的问题是:
答案 0 :(得分:7)
你是对的,如果你只查询字段数组中a的值,那么从某种意义上说,这两个索引都可以帮助你提高查询效率。
但是,请查看以下3个查询:
> db.zaid.save({field : [{a: 1}, {b: 2}, {c: 3}] });
> db.zaid.ensureIndex({field:1});
> db.zaid.ensureIndex({"field.a":1});
#Query 1
> db.zaid.find({"field.a":1})
{ "_id" : ObjectId("50b4be3403634cff61158dd0"), "field" : [ { "a" : 1 }, { "b" : 2 }, { "c" : 3 } ] }
> db.zaid.find({"field.a":1}).explain();
{
"cursor" : "BtreeCursor field.a_1",
"nscanned" : 1,
"nscannedObjects" : 1,
"n" : 1,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : true,
"indexOnly" : false,
"indexBounds" : {
"field.a" : [
[
1,
1
]
]
}
}
#Query 2
> db.zaid.find({"field.b":1}).explain();
{
"cursor" : "BasicCursor",
"nscanned" : 1,
"nscannedObjects" : 1,
"n" : 0,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
#Query 3
> db.zaid.find({"field":{b:1}}).explain();
{
"cursor" : "BtreeCursor field_1",
"nscanned" : 0,
"nscannedObjects" : 0,
"n" : 0,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : true,
"indexOnly" : false,
"indexBounds" : {
"field" : [
[
{
"b" : 1
},
{
"b" : 1
}
]
]
}
}
请注意,即使您为数组建立了索引,第二个查询也没有索引,但第三个查询会执行索引。根据您打算查询数据的方式选择索引与考虑索引本身是否符合您的需求一样重要。在Mongo中,如果不小心,索引的结构可以并且确实会对查询的性能产生很大的影响。我认为这解释了你的第一个问题。
您的第二个问题有点开放,但我认为答案再次取决于您对查询数据的期望。如果您只对匹配“fields.a”的值感兴趣,那么您应该在内存中为您可能需要的其他索引节省空间。但是,如果您同样有可能查询数组中的任何项目,并且您有理由确定该数组不会无限增长(从不在数组上索引,该数组可能会随着时间的推移而增长到未绑定的大小。一旦数组在BSON中达到1024字节,将无法索引文档。),那么你应该索引整个数组。这方面的一个例子可能是一张扑克牌手的文件,其中包含一个描述用户手中每张牌的阵列。您可以对此数组进行索引,而不必担心超出索引大小边界,因为一只手永远不会超过52张卡。