使用limit()和#x2B;时,MongoDB find()查询会扫描文档两次(使用重复的光标);排序()?

使用limit()和#x2B;时,MongoDB find()查询会扫描文档两次(使用重复的光标);排序()?,mongodb,Mongodb,我对MongoDB还相当陌生,尽管我还没有找到对我所看到的东西的解释 当我运行以下查询时,我有一个大约200个文档的小数据集: db.tweets.find({user:22438186}) 我在9得到n/nscannedObjects/nscanned/nscannedObjectsAllPlans/nscannedallplan。光标为BtreeCursor用户_1。一切都好 介绍排序() 如果我将排序附加到查询: db.tweets.find({user:22438186}).sort(

我对MongoDB还相当陌生,尽管我还没有找到对我所看到的东西的解释

当我运行以下查询时,我有一个大约200个文档的小数据集:
db.tweets.find({user:22438186})
我在9得到n/nscannedObjects/nscanned/nscannedObjectsAllPlans/nscannedallplan。光标为BtreeCursor用户_1。一切都好


介绍排序() 如果我将排序附加到查询:
db.tweets.find({user:22438186}).sort({created\u at:1})
nscannedObjectsAllPlans/nscannedAllPlans已增至30。我可以在allPlans字段下看到:

BtreeCursor在\u 1处创建\u扫描了21个文档并匹配了2个?我不确定这里发生了什么,因为我认为
sort()
应用于
find()
返回的文档,它似乎是用户索引中的9。在写这篇文章的过程中,我从allPlans字段收集到,出于某种原因,它也在使用我创建的_at_1索引


限制(>n)与Sort()组合==重复光标和文档扫描? 当我追加
limit(10)
或更高时,n保持在9,nscannedObjects/nscanned都在18并且nscannedObjectsAllPlans/nscannedAllPlans现在返回60为什么除n以外的所有对象都加倍了?光标现在是QueryOptimizerCursor,my
explain(true)
结果中有一个子句字段,两个子对象完全相同,相同的光标使用了两次,导致了重复?这种行为正常吗

{
"cursor" : "BtreeCursor user_1",
"isMultiKey" : false,
"n" : 9,
"nscannedObjects" : 9,
"nscanned" : 9,
"scanAndOrder" : true,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
    "user" : [ 
        [ 
            22438186, 
            22438186
        ]
    ]
}
}
我尝试了几个不同的限制值,注意到使用9的限制时,nscannedObjects/nscanned都返回到9的值,nscannedObjects/nscannedAllPlans下降到29,随着限制的减小,下降了1

但是,在子句下,第二个子对象与限制查询10及以上的查询不同。光标字段现在显示BtreeCursor省略用户_1出于某种原因,所有n个字段的值均为0,而不是9,此外,对象的其余部分是相同的。对于所有这些限制查询,allPlans字段列出了子句字段和在_1处创建的BtreeCursor的另一个字段(用作限制为1的查询的光标)


实际问题 那么,当
find()
中同时使用
limit()
sort()
时,究竟是什么原因导致我的文档被扫描两次呢?只有当限制超过nscannedObjects或nscanned时,问题才会出现。仅使用
limit()
sort()
进行查询时,不会扫描两次文档

更新 抱歉造成混淆,第一个代码块在allplan字段下显示光标数据。实际使用的光标是
*BtreeCursor user\u 1*

第二个代码块来自具有
limit()
sort()
的查询。我提供了子句下列出的游标数据,子句字段列出了相同的游标信息两次(重复)。该查询的实际光标字段是
*QueryOptimizerCursor*
。子句下的重复游标是
*BtreeCursor user\u 1*

此后,我添加了一个复合索引{user:1,创建了_at:1},n个字段的结果是9,18。无论
limit()
值或使用
sort()
。出于某种原因,在allPlans下,我的原始用户id 1索引仍然与新的复合索引一起运行。如果对查询应用了限制,而不是使用索引用户\u id\u 1/BtreeCursor用户\u 1,则将使用带有子句中两个游标的QueryOptimizerCursor

我一直在进一步研究这个问题,似乎查询计划器并行使用其他索引并选择最佳索引结果?我不确定是否每次执行此查询时都会再次发生此“竞争”,或者是否缓存了它

db.tweets.find({user:22438186}).sort({created_at:1}).limit(10)
在不使用复合索引的情况下运行查询会产生以下结果:

{
"clauses" : [ 
    {
        "cursor" : "BtreeCursor user_1",
        "isMultiKey" : false,
        "n" : 9,
        "nscannedObjects" : 9,
        "nscanned" : 9,
        "scanAndOrder" : true,
        "indexOnly" : false,
        "nChunkSkips" : 0,
        "indexBounds" : {
            "user" : [ 
                [ 
                    22438186, 
                    22438186
                ]
            ]
        }
    }, 
    {
        "cursor" : "BtreeCursor user_1",
        "isMultiKey" : false,
        "n" : 9,
        "nscannedObjects" : 9,
        "nscanned" : 9,
        "scanAndOrder" : true,
        "indexOnly" : false,
        "nChunkSkips" : 0,
        "indexBounds" : {
            "user" : [ 
                [ 
                    22438186, 
                    22438186
                ]
            ]
        }
    }
],
"cursor" : "QueryOptimizerCursor",
"n" : 9,
"nscannedObjects" : 18,
"nscanned" : 18,
"nscannedObjectsAllPlans" : 60,
"nscannedAllPlans" : 60,
"scanAndOrder" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"allPlans" : [ 
    {
        "clauses" : [ 
            {
                "cursor" : "BtreeCursor user_1",
                "isMultiKey" : false,
                "n" : 9,
                "nscannedObjects" : 9,
                "nscanned" : 9,
                "scanAndOrder" : true,
                "indexOnly" : false,
                "nChunkSkips" : 0,
                "indexBounds" : {
                    "user" : [ 
                        [ 
                            22438186, 
                            22438186
                        ]
                    ]
                }
            }, 
            {
                "cursor" : "BtreeCursor user_1",
                "isMultiKey" : false,
                "n" : 9,
                "nscannedObjects" : 9,
                "nscanned" : 9,
                "scanAndOrder" : true,
                "indexOnly" : false,
                "nChunkSkips" : 0,
                "indexBounds" : {
                    "user" : [ 
                        [ 
                            22438186, 
                            22438186
                        ]
                    ]
                }
            }
        ],
        "cursor" : "QueryOptimizerCursor",
        "n" : 9,
        "nscannedObjects" : 18,
        "nscanned" : 18,
        "scanAndOrder" : false,
        "nChunkSkips" : 0
    }, 
    {
        "cursor" : "BtreeCursor created_at_1",
        "isMultiKey" : false,
        "n" : 3,
        "nscannedObjects" : 42,
        "nscanned" : 42,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nChunkSkips" : 0,
        "indexBounds" : {
            "created_at" : [ 
                [ 
                    {
                        "$minElement" : 1
                    }, 
                    {
                        "$maxElement" : 1
                    }
                ]
            ]
        }
    }
],
"server" : "HOME-PC:27017",
"filterSet" : false,
"stats" : {
    "type" : "KEEP_MUTATIONS",
    "works" : 43,
    "yields" : 0,
    "unyields" : 0,
    "invalidates" : 0,
    "advanced" : 9,
    "needTime" : 32,
    "needFetch" : 0,
    "isEOF" : 1,
    "children" : [ 
        {
            "type" : "OR",
            "works" : 42,
            "yields" : 0,
            "unyields" : 0,
            "invalidates" : 0,
            "advanced" : 9,
            "needTime" : 32,
            "needFetch" : 0,
            "isEOF" : 1,
            "dupsTested" : 18,
            "dupsDropped" : 9,
            "locsForgotten" : 0,
            "matchTested_0" : 0,
            "matchTested_1" : 0,
            "children" : [ 
                {
                    "type" : "SORT",
                    "works" : 21,
                    "yields" : 0,
                    "unyields" : 0,
                    "invalidates" : 0,
                    "advanced" : 9,
                    "needTime" : 10,
                    "needFetch" : 0,
                    "isEOF" : 1,
                    "forcedFetches" : 0,
                    "memUsage" : 6273,
                    "memLimit" : 33554432,
                    "children" : [ 
                        {
                            "type" : "FETCH",
                            "works" : 10,
                            "yields" : 0,
                            "unyields" : 0,
                            "invalidates" : 0,
                            "advanced" : 9,
                            "needTime" : 0,
                            "needFetch" : 0,
                            "isEOF" : 1,
                            "alreadyHasObj" : 0,
                            "forcedFetches" : 0,
                            "matchTested" : 0,
                            "children" : [ 
                                {
                                    "type" : "IXSCAN",
                                    "works" : 10,
                                    "yields" : 0,
                                    "unyields" : 0,
                                    "invalidates" : 0,
                                    "advanced" : 9,
                                    "needTime" : 0,
                                    "needFetch" : 0,
                                    "isEOF" : 1,
                                    "keyPattern" : "{ user: 1 }",
                                    "isMultiKey" : 0,
                                    "boundsVerbose" : "field #0['user']: [22438186.0, 22438186.0]",
                                    "yieldMovedCursor" : 0,
                                    "dupsTested" : 0,
                                    "dupsDropped" : 0,
                                    "seenInvalidated" : 0,
                                    "matchTested" : 0,
                                    "keysExamined" : 9,
                                    "children" : []
                                }
                            ]
                        }
                    ]
                }, 
                {
                    "type" : "SORT",
                    "works" : 21,
                    "yields" : 0,
                    "unyields" : 0,
                    "invalidates" : 0,
                    "advanced" : 9,
                    "needTime" : 10,
                    "needFetch" : 0,
                    "isEOF" : 1,
                    "forcedFetches" : 0,
                    "memUsage" : 6273,
                    "memLimit" : 33554432,
                    "children" : [ 
                        {
                            "type" : "FETCH",
                            "works" : 10,
                            "yields" : 0,
                            "unyields" : 0,
                            "invalidates" : 0,
                            "advanced" : 9,
                            "needTime" : 0,
                            "needFetch" : 0,
                            "isEOF" : 1,
                            "alreadyHasObj" : 0,
                            "forcedFetches" : 0,
                            "matchTested" : 0,
                            "children" : [ 
                                {
                                    "type" : "IXSCAN",
                                    "works" : 10,
                                    "yields" : 0,
                                    "unyields" : 0,
                                    "invalidates" : 0,
                                    "advanced" : 9,
                                    "needTime" : 0,
                                    "needFetch" : 0,
                                    "isEOF" : 1,
                                    "keyPattern" : "{ user: 1 }",
                                    "isMultiKey" : 0,
                                    "boundsVerbose" : "field #0['user']: [22438186.0, 22438186.0]",
                                    "yieldMovedCursor" : 0,
                                    "dupsTested" : 0,
                                    "dupsDropped" : 0,
                                    "seenInvalidated" : 0,
                                    "matchTested" : 0,
                                    "keysExamined" : 9,
                                    "children" : []
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}
}
使用复合索引:

{
"cursor" : "BtreeCursor user_1_created_at_1",
"isMultiKey" : false,
"n" : 9,
"nscannedObjects" : 9,
"nscanned" : 9,
"nscannedObjectsAllPlans" : 18,
"nscannedAllPlans" : 18,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
    "user" : [ 
        [ 
            22438186, 
            22438186
        ]
    ],
    "created_at" : [ 
        [ 
            {
                "$minElement" : 1
            }, 
            {
                "$maxElement" : 1
            }
        ]
    ]
},
"allPlans" : [ 
    {
        "cursor" : "BtreeCursor user_1_created_at_1",
        "isMultiKey" : false,
        "n" : 9,
        "nscannedObjects" : 9,
        "nscanned" : 9,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nChunkSkips" : 0,
        "indexBounds" : {
            "user" : [ 
                [ 
                    22438186, 
                    22438186
                ]
            ],
            "created_at" : [ 
                [ 
                    {
                        "$minElement" : 1
                    }, 
                    {
                        "$maxElement" : 1
                    }
                ]
            ]
        }
    }, 
    {
        "clauses" : [ 
            {
                "cursor" : "BtreeCursor user_1",
                "isMultiKey" : false,
                "n" : 0,
                "nscannedObjects" : 9,
                "nscanned" : 9,
                "scanAndOrder" : true,
                "indexOnly" : false,
                "nChunkSkips" : 0,
                "indexBounds" : {
                    "user" : [ 
                        [ 
                            22438186, 
                            22438186
                        ]
                    ]
                }
            }, 
            {
                "cursor" : "BtreeCursor ",
                "isMultiKey" : false,
                "n" : 0,
                "nscannedObjects" : 0,
                "nscanned" : 0,
                "scanAndOrder" : true,
                "indexOnly" : false,
                "nChunkSkips" : 0,
                "indexBounds" : {
                    "user" : [ 
                        [ 
                            22438186, 
                            22438186
                        ]
                    ]
                }
            }
        ],
        "cursor" : "QueryOptimizerCursor",
        "n" : 0,
        "nscannedObjects" : 9,
        "nscanned" : 9,
        "scanAndOrder" : false,
        "nChunkSkips" : 0
    }
],
"server" : "HOME-PC:27017",
"filterSet" : false,
"stats" : {
    "type" : "LIMIT",
    "works" : 11,
    "yields" : 0,
    "unyields" : 0,
    "invalidates" : 0,
    "advanced" : 9,
    "needTime" : 0,
    "needFetch" : 0,
    "isEOF" : 1,
    "children" : [ 
        {
            "type" : "FETCH",
            "works" : 11,
            "yields" : 0,
            "unyields" : 0,
            "invalidates" : 0,
            "advanced" : 9,
            "needTime" : 0,
            "needFetch" : 0,
            "isEOF" : 1,
            "alreadyHasObj" : 0,
            "forcedFetches" : 0,
            "matchTested" : 0,
            "children" : [ 
                {
                    "type" : "IXSCAN",
                    "works" : 10,
                    "yields" : 0,
                    "unyields" : 0,
                    "invalidates" : 0,
                    "advanced" : 9,
                    "needTime" : 0,
                    "needFetch" : 0,
                    "isEOF" : 1,
                    "keyPattern" : "{ user: 1, created_at: 1 }",
                    "isMultiKey" : 0,
                    "boundsVerbose" : "field #0['user']: [22438186.0, 22438186.0], field #1['created_at']: [MinKey, MaxKey]",
                    "yieldMovedCursor" : 0,
                    "dupsTested" : 0,
                    "dupsDropped" : 0,
                    "seenInvalidated" : 0,
                    "matchTested" : 0,
                    "keysExamined" : 9,
                    "children" : []
                }
            ]
        }
    ]
}
}

希望这能消除困惑。

如果您看到
explain()
计划,您可以看到:

db.tweets.find({user:22438186})
使用
user_1
索引

db.tweets.find({user:22438186}).sort({created_at:1})
使用
created_at_1
索引

这表明mongodb选择了
created_at_1
而不是
user_1
,因为排序操作在使用索引时性能更好,并且排序操作基于
created_at
字段。这使得
mongodb
忽略
user\u 1
索引并执行
完全收集扫描

因此,我们需要在这些情况下仔细定义我们的目标。如果我们在
user\u 1
created\u at\u 1
上都有一个复合索引,则不会进行全表扫描,mongodb将选择同时支持
find
sort
操作的索引,在这种情况下,该索引将是复合索引

对mongoDB为什么使用
QueryOptimizerCursor
光标有一个很好的解释

nscannedObjectsAllPlans/nscannedAllPlans下降到29

您不必担心这两个参数,它们是mongodb为选择适当索引而执行的所有计划的组合扫描的表示

nscannedObjectsAllPlans是一个反映 在数据库操作期间扫描所有查询计划的文档

NSCanendallPlans是一个反映 在查询过程中扫描所有查询计划的文档或索引项 数据库操作

这些线是从

那么,当limit()和sort()都在一个应用程序中使用时,究竟是什么原因导致我的文档被扫描两次呢
db.tweets.find({user:22438186})