簡體   English   中英

mongodb不使用$ exists和$ elemMatch的索引

[英]mongodb does not use indexes for $exists and $elemMatch

我的文檔結構如下所示

{
    "_id" : "311acd33a0ae8dcc3101246f90af9dc5",
    "created_datetime" : ISODate("2013-04-05T10:35:31.143Z"),
    "installs" : [
        {
            "status" : 1,
            "app" : "xyz",
            "reg_id" : "AVJyaIFI2Q8v93YmOHI5kEOVoCLbd4CAUyVK9zLrC1QCiBcl_bw89i5PvhEuTKmxtb4x130vjMyo78zPI7cedErcRv_Jjn0BN3Wq40hhg",
            "last_action_datetime" : ISODate("2013-04-05T10:35:31.143Z"),
            "version" : "2"
        },
        {
            "status" : 1,
            "app" : "abc",                                                
            "reg_id" : "AVJyaIFI2Q8v93YmOHI5kEOVoCLbd4CAUyVK9zLrC1QCiBcl_bw89i5PvhEuTKmxtb4x130vjMyo78zPI7cedErcRv_Jjn0BN3Wq40hhg",
            "last_action_datetime" : ISODate("2013-04-05T10:35:31.143Z"),
            "version" : "5"
        },
        {
            "status" : 1,
            "app" : "pqr",                                                
            "last_action_datetime" : ISODate("2013-04-06T10:35:31.143Z"),
            "version" : "1"
        },
    ],
    "last_update" : ISODate("2013-04-12T06:26:46.333Z"),
    "num_updates" : 9,
    .....
}

和我有上的復合索引'install.reg_id''installs.status'和單一索引'installs.status'

現在我想找到所有文件,其中至少在installs元素中包含reg_id ,並且其status為1.所以我查詢

db.users.find({'installs': {'$elemMatch': {'reg_id': {'$exists':  true}, 'status': 1}}}).explain()

我明白了

{
        "cursor" : "BtreeCursor installs.status_1",
        "isMultiKey" : true,
        "n" : 1447034,
        "nscannedObjects" : 1720864,
        "nscanned" : 1720864,
        "nscannedObjectsAllPlans" : 1720864,
        "nscannedAllPlans" : 1720864,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 13072,
        "nChunkSkips" : 0,
        "millis" : 11063,
        "indexBounds" : {
                "installs.status" : [
                        [
                                1,
                                1
                        ]
                ]
        },
        "server" : "####:27017"
}

所以這里應該使用復合索引但是沒有使用。 我認為$elemMatch是罪魁禍首所以我做了這個查詢

db.users.find({'installs.reg_id': {'$exists':  true}}).explain()

我明白了

{
        "cursor" : "BasicCursor",
        "isMultiKey" : false,
        "n" : 2947446,
        "nscannedObjects" : 3184871,
        "nscanned" : 3184871,
        "nscannedObjectsAllPlans" : 3184871,
        "nscannedAllPlans" : 3184871,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 23865,
        "nChunkSkips" : 0,
        "millis" : 16172,
        "indexBounds" : {

        },
        "server" : "####:27017"
}

這表明查詢未使用任何索引。

知道這里出了什么問題嗎?

更新:添加提示確實使查詢使用索引

db.users.find({'installs': {'$elemMatch': {'reg_id': {'$exists':  true}, 'status': 1}}}).hint({"installs.reg_id":1,"installs.status":1}).explain()

回報

{
        "cursor" : "BtreeCursor installs.reg_id_1_installs.status_1",
        "isMultiKey" : true,
        "n" : 1451589,
        "nscannedObjects" : 2464985,
        "nscanned" : 4373261,
        "nscannedObjectsAllPlans" : 2464985,
        "nscannedAllPlans" : 4373261,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 20170,
        "nChunkSkips" : 0,
        "millis" : 106353,
        "indexBounds" : {
                "installs.reg_id" : [
                        [
                                {
                                        "$minElement" : 1
                                },
                                {
                                        "$maxElement" : 1
                                }
                        ]
                ],
                "installs.status" : [
                        [
                                1,
                                1
                        ]
                ]
        },
        "server" : "####:27017"
}

這里使用復合索引。

沒有什么不對的。 查詢優化器正在選擇提供更好性能/選擇性的索引。

您可以通過“提示”查詢使用您希望它使用的索引來確認這一點,並比較需要掃描的元素和文檔的數量,以找到它需要返回的內容。

看一下你的解釋,我可以看到reg_id存在於你希望查詢使用的索引中超過92.5%的索引條目。 這不是很有選擇性。 使用您希望它使用的索引僅縮小3.1M文檔/條目到2.9M - 不是很好。

使用status_1索引,它立即將“候選者”縮小到1.7M,現在通過所有這些,它發現1.4M有reg_id。

有更多的選擇性指標是關鍵,但不要忘了,在這種情況下,你問它返回1.4M的文件,所以很難是非常有選擇性的,當這許多文件需要掃描。

另一件事是平等,對於索引(甚至不等於)而言,這比{$ exists}更有效。 甚至{$ ne:null}也會比$存在更好 - 通常,依靠使用$ exists或甚至不等式的查詢來表示相等性或較小范圍的查詢(使用索引時)不是一個好主意。

更多信息可以在這里找到: http//docs.mongodb.org/manual/applications/indexes/ ,特別是在這里: http//docs.mongodb.org/manual/tutorial/create-queries-that-ensure-選擇性/

我有同樣的問題。 它似乎是針對2.7(Due:01 / Aug / 14)版本的文檔錯誤:

https://jira.mongodb.org/browse/SERVER-2348

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM