不同字段中gte,lte和sort的索引

时间:2014-07-11 05:47:04

标签: mongodb

我对mongodb的查询是:

   db.records.find({ from_4: { '$lte': 7495 }, to_4: { '$gte': 7495 } }).sort({ from_11: 1 }).skip(60000).limit(100).hint("from_4_1_to_4_-1_from_11_1").explain()

我建议它应该使用索引from_4_1_to_4_-1_from_11_1

{
  "from_4": 1,
  "to_4": -1,
  "from_11": 1
}

但得到了错误:

error: {
    "$err" : "Runner error: Overflow sort stage buffered data usage of 33555322 bytes exceeds internal limit of 33554432 bytes",
    "code" : 17144
} at src/mongo/shell/query.js:131

如何避免此错误?

也许我应该创建另一个索引,更符合我的查询。

我也尝试使用所有升序字段编制索引...

{
      "from_4": 1,
      "to_4": 1,
      "from_11": 1
    }

......但是同样的错误。

P.S。我注意到,当我删除跳过命令时...

> db.records.find({ from_4: { '$lte': 7495 }, to_4: { '$gte': 7495 } }).sort({ from_11: 1 }).limit(100).hint("from_4_1_to_4_-1_from_11_1").explain()

...没关系,我得到了解释输出,但它说我不使用索引:"indexOnly" : false

{
    "clauses" : [
        {
            "cursor" : "BtreeCursor from_4_1_to_4_-1_from_11_1",
            "isMultiKey" : false,
            "n" : 100,
            "nscannedObjects" : 61868,
            "nscanned" : 61918,
            "scanAndOrder" : true,
            "indexOnly" : false,
            "nChunkSkips" : 0,
            "indexBounds" : {
                "from_4" : [
                    [
                        -Infinity,
                        7495
                    ]
                ],
                "to_4" : [
                    [
                        Infinity,
                        7495
                    ]
                ],
                "from_11" : [
                    [
                        {
                            "$minElement" : 1
                        },
                        {
                            "$maxElement" : 1
                        }
                    ]
                ]
            }
        },
        {
            "cursor" : "BtreeCursor ",
            "isMultiKey" : false,
            "n" : 0,
            "nscannedObjects" : 0,
            "nscanned" : 0,
            "scanAndOrder" : true,
            "indexOnly" : false,
            "nChunkSkips" : 0,
            "indexBounds" : {
                "from_4" : [
                    [
                        -Infinity,
                        7495
                    ]
                ],
                "to_4" : [
                    [
                        Infinity,
                        7495
                    ]
                ],
                "from_11" : [
                    [
                        {
                            "$minElement" : 1
                        },
                        {
                            "$maxElement" : 1
                        }
                    ]
                ]
            }
        }
    ],
    "cursor" : "QueryOptimizerCursor",
    "n" : 100,
    "nscannedObjects" : 61868,
    "nscanned" : 61918,
    "nscannedObjectsAllPlans" : 61868,
    "nscannedAllPlans" : 61918,
    "scanAndOrder" : false,
    "nYields" : 832,
    "nChunkSkips" : 0,
    "millis" : 508,
    "server" : "myMac:27026",
    "filterSet" : false
}

P.P.S 我看过mongo db tutorial about sort indexes并认为我做得很好。

更新

累积 @dark_shadow 建议我创建了两个以上的索引:

db.records.ensureIndex({from_11: 1})

db.records.ensureIndex({from_11: 1, from_4: 1, to_4: 1})

和索引db.records.ensureIndex({from_11: 1})成为我的需要:

db.records.find({ from_4: { '$lte': 7495 }, to_4: { '$gte': 7495 } }).sort({ from_11: 1 }).skip(60000).limit(100).explain()
{
    "cursor" : "BtreeCursor from_11_1",
    "isMultiKey" : false,
    "n" : 100,
    "nscannedObjects" : 90154,
    "nscanned" : 90155,
    "nscannedObjectsAllPlans" : 164328,
    "nscannedAllPlans" : 164431,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 1284,
    "nChunkSkips" : 0,
    "millis" : 965,
    "indexBounds" : {
        "from_11" : [
            [
                {
                    "$minElement" : 1
                },
                {
                    "$maxElement" : 1
                }
            ]
        ]
    },
    "server" : "myMac:27025",
    "filterSet" : false
}

1 个答案:

答案 0 :(得分:3)

当您使用范围查询(并且您)时,mongo查询无论如何都不要使用索引进行排序。您可以通过查看" scanAndOrder"来检查这一点。测试查询后,您的explain()的值。如果该值存在且为true,则表示它将结果集排序在内存中(扫描和顺序),而不是直接使用索引。这就是您在第一个查询中收到错误的原因。

正如Mongodb文档所说,

对于不使用索引的内存中排序,sort()操作明显变慢。 sort()操作将在使用32兆字节的内存时中止。

您可以在内存排序中使用limit(100)来检查第一个查询中scanAndOrder的值。

您的第二个查询有效,因为您已经使用了限制,因此它只能对100个可以在内存中完成的文档进行排序。

为什么" indexOnly" :false

这只是表明您希望返回的所有字段都不在索引中,BtreeCursor表示索引用于查询(BasicCursor意味着它没有)。要使其成为indexOnly查询,您需要在投影中仅返回索引中的那些字段(即:{_ id:0,from_4:1,to_4:1,from_11:1})。这意味着它永远不会触及数据本身,只能从索引中返回您需要的所有内容。一旦修改了查询以仅返回提到的字段,您也可以使用说明进行检查。

现在,你会感到困惑。它是否使用索引?对于排序,它不会使用索引,但是查询它是使用索引。这就是你获得BtreeCusrsor的原因(你应该也看到了你的索引名称)。

现在,要解决您的问题,您可以创建两个索引:

{
      "from_4": 1,
      "to_4": 1,
}

{
    "from_11" : 1
}

然后通过仔细观察scanOrder值来查看它现在是否给出错误或使用索引进行排序。

还有一项工作: 更改compund索引的顺序:

{
      "FROM_11" : 1,
      "from_4": 1,
      "to_4": 1,
}

不确定这种方法。它应该有希望。

看看你想要得到什么,你也可以用{from_11:-1} .limit(1868)进行排序。

我希望我现在能让事情变得更加清晰。请根据我的建议做一些测试。如果您遇到任何问题,请告诉我。我们可以继续努力。

由于