我在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);
查询运行大约1300毫秒,这是相当慢的。现在,当我删除$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);
该查询仅在1毫秒内运行。
解释第一个查询(使用$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驱动程序的$query
运算符的情况下编写查询?
答案 0 :(得分:0)
在mongodb docs状态
不要混合查询表单。如果使用$ query格式,请不要追加 游标方法到find()。要修改查询,请使用元查询 运营商,如$ explain。
因此,在您的情况下,我认为省略了.limit(20)
使用,并导致您的查询继续查看所有文档的所有集合。
可能是c#
驱动程序上的错误。
答案 1 :(得分:0)
好的,由于limit()
没有元查询运算符而$maxScan
具有不同的含义,我只需要在更新字段上添加一个条件,例如大于上个月:{ {1}}。这样我的查询将在50毫秒内返回。如果返回的文档少于限制,我可以扩展日期过滤器并再次运行查询。