MongoDB $或+ sort + index。如何避免在内存中排序?

时间:2017-04-10 12:25:04

标签: mongodb sorting indexing

我有一个问题是为我的mongo查询生成正确的索引,这将避免SORT阶段。在我的情况下,我甚至不确定这是否可行。所以这是我的执行统计查询:

db.getCollection('test').find(
{
    "$or" : [
    {
        "a" : { "$elemMatch" : { "_id" : { "$in" : [4577] } } }, 
        "b" : { "$in" : [290] }, 
        "c" : { "$in" : [35, 49, 57, 101, 161, 440] }, 
        "d" : { "$lte" : 399 }
    },
    { 
        "e" : { "$elemMatch" : { "numbers" : { "$in" : ["1K0407151AC", "0K20N51150A"]  } } },
        "d" : { "$lte" : 399 }
     }] 
})
.sort({ "X" : 1, "d" : 1, "Y" : 1, "Z" : 1 }).explain("executionStats")

字段' m' ,' a'并且' e'是数组,这就是为什么' m'不包含在任何索引中。

如果查看execution stats屏幕截图,您会看到内存使用率非常接近最大值,不幸的是我遇到了因为32MB限制而无法执行查询的情况。

$或查询的第一部分的索引:     {         " a._id" :1,         " X" :1,         " d" :1,         " Y" :1,         " Z" :1,         " B" :1,         " C" :1     }

$或查询的第二部分的索引: {     " e.numbers" :1,     " X" :1,     " d" :1,     " Y" :1,     " Z" :1 }

索引由查询使用,但不用于排序。而不是SORT阶段我也希望看到SORT_MERGE阶段,但现在没有成功。如果我在$或单独运行部分查询,他们可以使用索引来避免在内存中进行排序。作为一种解决方法,它是可以的,但我需要通过应用程序合并并求助结果。

MongoDB版本是3.4.2。我检查了thatthat问题。我的查询是结果。可能我错过了什么?

编辑:mongo文档看起来像这样:

{
    "_id" : "290_440_K760A03",
    "Z" : "K760A03",
    "c" : 440,
    "Y" : "NPS",
    "b" : 290,
    "X" : "Schlussleuchte",
    "e" : [ 
        {
            "..." : 184,
            "numbers" : [ 
                "0K20N51150A"
            ]
        }
    ],
    "a" : [ 
        {
            "_id" : 4577,
            "..." : [ 
                {
                    "..." : [ 
                        {
                            "..." : "R",
                        }
                    ]
                }
            ]
        }, 
        {
            "_id" : 4578            
        }
    ],
    "d" : 101,
    "m" : [ 
        "AT", 
        "BR", 
        "CH"
    ],
    "moreFields":"..."
}

编辑2 :删除了提交的" m"从查询到降低复杂性和attached测试集合转储给想要帮助的人:)

1 个答案:

答案 0 :(得分:0)

这是解决方案 - 我刚刚在我的测试集合中添加了一个文档,如您的问题所示(编辑部分)。然后我在下面创建了四个指数 -

 1. {"m":1,"b":1,"c":1,"X":1,"d":1,"Y":1,"Z":1}
 2. {"a._id":1,"b":1,"c":1,"X":1,"d":1,"Y":1,"Z":1}
 3. {"m":1,"X":1,"d":1,"Y":1,"Z":1}
 4. {"e.numbers":1,"X":1,"d":1,"Y":1,"Z":1}

当我执行给定的执行统计查询时,它会按预期显示SORT_MERGE状态。

以下是解释 - MongoDB有一个名为equality-sort-range的东西,它告诉我们应该如何创建索引。我只是遵循这条规则并按顺序保留索引。所以索引应该是{Equality fields, "X":1,"d":1,"Y":1,"Z":1, Range fields}。您可以看到查询的字段范围为" d"只有("d" : { "$lte" : 101 })但是" d"已经在索引("X":1,"d":1,"Y":1,"Z":1)的SORT字段中进行了覆盖,因此我们可以从索引末尾跳过范围部分(即字段" d")。

如果" d"没有处于排序/等式谓词然后我会把它作为范围索引字段的索引,我的索引看起来像{Equality fields, "X":1,"Y":1,"Z":1,"d":1}

现在我的索引是{Equality fields, "X":1,"d":1,"Y":1,"Z":1},我只关心平等字段。因此,为了找出相等的字段,我只是检查查询查找谓词,我发现有两个条件由OR运算符组合。

  • 第一个条件在"a._id", "b", "c", "m"上具有相等性(" d"具有范围,而不是相等)。所以我需要创建一个像"a._id":1,"m":1,"b":1,"c":1,"X":1,"d":1,"Y":1,"Z":1这样的索引,但这会产生错误,因为它有两个数组字段" a_id"和" m"。正如我们所知,Mongo不允许compound index on parallel arrays所以它会失败。所以我创建了两个单独的索引,只允许Mongo使用查询规划器选择的任何内容。因此我创建了第一个和第二个索引。
  • OR运算符的第二个条件是" e.numbers"和" m"。两者都是数组字段,所以我必须为第一个条件创建两个索引,以及我如何获得第三个和第四个索引。

现在我们知道单个查询一次只能使用一个索引,所以我需要创建这些索引,因为我不知道OR运算符的哪个分支将被执行。

注意:如果您担心索引的大小,那么您只能保留前两个索引和前两个索引。或者你也可以保留所有四个和提示mongo使用正确的索引,如果你在查询规划器之前就知道它。