包装在$ query运算符中的MongoDB查询确实很慢

时间:2014-01-28 22:11:18

标签: c# mongodb

我在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运算符的情况下编写查询?

2 个答案:

答案 0 :(得分:0)

mongodb docs状态

  

不要混合查询表单。如果使用$ query格式,请不要追加   游标方法到find()。要修改查询,请使用元查询   运营商,如$ explain。

因此,在您的情况下,我认为省略了.limit(20)使用,并导致您的查询继续查看所有文档的所有集合。

可能是c#驱动程序上的错误。

答案 1 :(得分:0)

好的,由于limit()没有元查询运算符而$maxScan具有不同的含义,我只需要在更新字段上添加一个条件,例如大于上个月:{ {1}}。这样我的查询将在50毫秒内返回。如果返回的文档少于限制,我可以扩展日期过滤器并再次运行查询。