复合索引查询

时间:2015-03-15 07:50:05

标签: node.js mongodb mongoose

我有一个查询,我正在运行这是非常缓慢的,并且我正在尝试对其进行复合索引,正确地说,这里是新手。我已经完成了下面的索引只是想知道我是否已经正确地完成了它,似乎并没有产生任何影响= /

Match.statics.getMatchesForDay = function (day, liveOnly, excludedAreas, excludedCompetitions, doneCallback) {

    var include = "-_id match_id title date_utc date_iso _grouping match_info.period match_info.minute match_info.minute_extra match_info.full_time team_a team_b status time_utc";

    var filter = {
        date_utc: day,
        score_coverage: true,
        "_grouping._area.area_id": {
            // Only include active areas
            "$nin": excludedAreas
        },
        "_grouping._competition.competition_id": {
            // Only include active competitions
            "$nin": excludedCompetitions
        }
    };

    if (liveOnly)
        filter.status = "Playing";

    this.find(filter).sort({
        "_grouping._area.name": 1, //Sort by asc
        "_grouping._competition.competition_id": 1, //Sort by asc
        "date_iso": 1, //Sort by asc
    }).select(include).exec(doneCallback);

};

Match.index({
    date_utc: -1,
    score_coverage: -1,
    "_grouping._area.area_id": 1,
    "_grouping._competition.competition_id": 1
}); 

Match.index({"_grouping._area.area_id": 1, "_grouping._competition.competition_id": 1, date_iso: 1}); 

我的.explain()输出:

{
    "cursor" : "BtreeCursor date_utc_1_score_coverage_-1__grouping._area.area_id_1__grouping._competition.competition_id_1",
    "isMultiKey" : false,
    "n" : 358,
    "nscannedObjects" : 358,
    "nscanned" : 358,
    "nscannedObjectsAllPlans" : 863,
    "nscannedAllPlans" : 863,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 6,
    "nChunkSkips" : 0,
    "millis" : 7,
    "indexBounds" : {
            "date_utc" : [
                    [
                            "2015-03-15",
                            "2015-03-15"
                    ]
            ],
            "score_coverage" : [
                    [
                            true,
                            true
                    ]
            ],
            "_grouping._area.area_id" : [
                    [
                            {
                                    "$minElement" : 1
                            },
                            {
                                    "$maxElement" : 1
                            }
                    ]
            ],
            "_grouping._competition.competition_id" : [
                    [
                            {
                                    "$minElement" : 1
                            },
                            {
                                    "$maxElement" : 1
                            }
                    ]
            ]
    },
    "server" : "xxxxx:27017",
    "filterSet" : false

}

除非它有效并且我挑剔,在一个小集合上它大约200ms,在较大的1-3s +上。目前,两者的$ nin都是空的。

感谢您的光临。

1 个答案:

答案 0 :(得分:1)

无论您使用什么索引,该查询都不会很快。让我们一步一步地看一下过滤器:

var filter = {
    date_utc: day,

到目前为止很好。可以索引等式查询。日期应具有足够高的选择性。它也可能提供良好的数据位置。

    score_coverage: true,

布尔值?坏事 - 索引本质上是树结构。但是,如果您的数据是单个布尔值,则只有两个可能的选项:true和false。 (选择性低)。这意味着树有一个true和一个false分支,其中包含 all 数据“下面”。这使得树本质上成为一个链表。它还会破坏局部性,因为更改值必须重新排列整个子树。将其移至末尾,并将其从索引中删除。

    "_grouping._area.area_id": {
        // Only include active areas
        "$nin": excludedAreas
    },

索引的工作方式类似于电话簿中的字母标记。你在找“john doe”吗?好的,查看从外面可见的字母“D”(索引),然后在“Do”中搜索“o”,依此类推。假设我给你一本电话簿,并要求你找到所有未命名为“Doe”的人。索引有帮助吗?不是真的,很容易跳过“Doe”。毕竟,无论如何你都需要经历整个事情。再次,this is a problem of low selectivity

    "_grouping._competition.competition_id": {
        // Only include active competitions
        "$nin": excludedCompetitions
    }

相同的论点,大量数据的$nin是不好的。

现在,排序:

this.find(filter).sort({
    "_grouping._area.name": 1, //Sort by asc
    "_grouping._competition.competition_id": 1, //Sort by asc
    "date_iso": 1, //Sort by asc
}).select(include).exec(doneCallback);

排序是相对昂贵的操作,因此您需要确保索引符合以下规则,因为数据已经在索引中排序:

equality criteria -- range criteria -- sort criteria

但是现在你已经将等式和范围标准中使用的date-area-competitionId的顺序转换为area-competitionId-date进行排序。

解决此问题需要了解问题域。我建议你尝试rearrange the data structure based on query selectivity / locality concerns查询应该很简单。