我有一个查询,我正在运行这是非常缓慢的,并且我正在尝试对其进行复合索引,正确地说,这里是新手。我已经完成了下面的索引只是想知道我是否已经正确地完成了它,似乎并没有产生任何影响= /
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都是空的。
感谢您的光临。
答案 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。 查询应该很简单。