我在MongoDB中有一个约有350K文件的集合。我有Updated
(降序)和SecondaryCategories
(升序)的复合指数。
db.Content.ensureIndex({ "Updated" : -1, "SecondaryCategories" : 1 },{ "name" : "Updated_SecondaryCategories", "background" : true });
我使用MongoDB的C#驱动程序使用lambda语法来构建查询:
IQueryable<Content> query = repo.GetAll()
.Where(
x =>
x.SecondaryCategories.ContainsAny(sel) &&
(x.Type == ContentType.News || x.Type == ContentType.FotoNews || x.Type == ContentType.LinkedNews || x.Type == ContentType.MediaNews) &&
x.Texts.Any(y => (int)y.Language == cultureId))
.OrderByDescending(x => x.Updated)
.Skip(skipItems)
.Take(count);
和我得到以下几点:
db.Content.find({ "$query" : { "SecondaryCategories" : { "$in" : [524, 615, 550, 546, 552, 617, 547, 549, 548, 613, 614, 551, 618, 545] }, "$or" : [{ "Type" : 4 }, { "Type" : 8 }, { "Type" : 32 }, { "Type" : 16 }], "Texts" : { "$elemMatch" : { "Language" : 0 } } }, $orderby: { Updated: -1 }}).limit(20);
查询大约为运行1300ms这很慢。现在,当我删除$query
经营者,我应该得到以下几点:
db.Content.find({ "SecondaryCategories" : { "$in" : [524, 615, 550, 546, 552, 617, 547, 549, 548, 613, 614, 551, 618, 545] }, "$or" : [{ "Type" : 4 }, { "Type" : 8 }, { "Type" : 32 }, { "Type" : 16 }], "Texts" : { "$elemMatch" : { "Language" : 0 } }}).sort({"Updated" : -1}).limit(20);
该查询只在1ms内运行。
解释第一个查询(用$query
运营商):
db.Content.find({ "$query" : { "SecondaryCategories" : { "$in" : [524, 615, 550, 546, 552, 617, 547, 549, 548, 613, 614, 551, 618, 545] }, "$or" : [{ "Type" : 4 }, { "Type" : 8 }, { "Type" : 32 }, { "Type" : 16 }], "Texts" : { "$elemMatch" : { "Language" : 0 } } }, $orderby: { Updated: -1 }, $explain: 1 }).limit(20).pretty();
{
"cursor" : "BtreeCursor Updated_SecondaryCategories multi",
"isMultiKey" : true,
"n" : 188173,
"nscannedObjects" : 188668,
"nscanned" : 337619,
"nscannedObjectsAllPlans" : 189056,
"nscannedAllPlans" : 338007,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 1,
"nChunkSkips" : 0,
"millis" : 1304,
"indexBounds" : {
"Updated" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"SecondaryCategories" : [
[
524,
524
],
[
545,
545
],
[
546,
546
],
[
547,
547
],
[
548,
548
],
[
549,
549
],
[
550,
550
],
[
551,
551
],
[
552,
552
],
[
613,
613
],
[
614,
614
],
[
615,
615
],
[
617,
617
],
[
618,
618
]
]
}
而对于第二(不$query
运营商):
db.Content.find({ "SecondaryCategories" : { "$in" : [524, 615, 550, 546, 552, 617, 547, 549, 548, 613, 614, 551, 618, 545] }, "$or" : [{ "Type" : 4 }, { "Type" : 8 }, { "Type" : 32 }, { "Type" : 16 }], "Texts" : { "$elemMatch" : { "Language" : 0 } }}).sort({"Updated" : -1}).limit(20).explain();
{
"cursor" : "BtreeCursor Updated_SecondaryCategories multi",
"isMultiKey" : true,
"n" : 20,
"nscannedObjects" : 29,
"nscanned" : 69,
"nscannedObjectsAllPlans" : 94,
"nscannedAllPlans" : 134,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"Updated" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"SecondaryCategories" : [
[
524,
524
],
[
545,
545
],
[
546,
546
],
[
547,
547
],
[
548,
548
],
[
549,
549
],
[
550,
550
],
[
551,
551
],
[
552,
552
],
[
613,
613
],
[
614,
614
],
[
615,
615
],
[
617,
617
],
[
618,
618
]
]
}
我实在无法理解查询这种行为差异。它似乎是第一个查询扫描通过338k文件,并返回188173,这是有限的,而第二个扫描只有69.
我的索引是否错误或我必须重写查询?如果没有使用C#MongoDB Driver的$query
运算符,是否有任何方法来编写查询?
你试过解释查询吗? http://docs.mongodb.org/manual/reference/operator/meta/query/#op._S_query - 我想你可能需要添加限制条款的查询文件本身,而不是'.limit' –
是的,我使用'$ explain:1'来解释第一个查询。我找不到任何其他限制方式。有'$ maxScan',但它只是限制扫描的文件数量。 – Villu89