MongoDB查询在使用$or运算符时变慢
我正试图对我的收藏MongoDB查询在使用$or运算符时变慢,mongodb,indexing,mongodb-query,Mongodb,Indexing,Mongodb Query,我正试图对我的收藏Audios var querySlow = { "palabra": { $regex: "^" + keywords, "$options": "i" }, $or: [{ "_p_pais": { $in: interested_accents } }, {
Audios
var querySlow = {
"palabra": {
$regex: "^" + keywords,
"$options": "i"
},
$or: [{
"_p_pais": {
$in: interested_accents
}
}, {
"languageCodeTatoeba": {
$in: interested_accents_tatoeba
}
}]
}; // takes 20 seconds
这实际上是非常非常慢,但是如果我删除任何$或
,它是非常非常快,例如:
var queryFast1 = {
"palabra": {
$regex: "^" + keywords,
"$options": "i"
},
$or: [{
"_p_pais": {
$in: interested_accents
}
}]
}; // takes less than 1 second
还是这个
var queryFast2 = {
"palabra": {
$regex: "^" + keywords,
"$options": "i"
},
$or: [{
"languageCodeTatoeba": {
$in: interested_accents_tatoeba
}
}]
}; // takes less than 1 second
这是慢速查询的.explain()
:
实际上,我不知道如何管理索引,是否应该为此集合创建索引???您的查询和索引存在一些问题: 1$或者使用不同的索引 MongoDB对一个查询只使用一个索引,涉及
$或
子句的查询除外。从页面:
通常,MongoDB只使用一个索引来完成大多数查询。但是,$or查询的每个子句可能使用不同的索引
另请参见本页:
也就是说,为了让MongoDB使用索引计算$or表达式,索引必须支持$or表达式中的所有子句
关于您的查询,您可以尝试重新安排查询,使$或子句成为顶级子句:
{$or: [
{"palabra": {...}, "_p_pais": {...} },
{"palabra": {...}, "languageCodeTatoeba": {...}}
]}
在这种形式下,MongoDB可以使用两个索引:
- 带有
palabra
和术语的复合索引,以及
- 带有
palabra
和languageCodeTatoeba
术语的复合索引
请使用explain(“executionStats”)
检查索引是否正确使用。您希望最小化的关键指标是文档数量(nReturned
)与检查的文档/密钥总数之比。比率越接近1,查询的选择性越高,性能越好
例如,如果MongoDB必须检查1000个文档(TotalDocsAdmined:1000
),但只返回10个文档(nReturned:10
),那么您的查询不是很有选择性(即10/1000的比率)。理想的查询将具有接近或等于1的比率,例如,nReturn:10,TotalDocsChecked:10
,比率为1(10/10)
有关explain()
的更多信息,请参阅:
2。索引太多
索引过多可能导致:
- 查询计划器选择一个次优索引,因为它不知道使用哪个索引,因为它们看起来都一样
- 插入/更新性能相对较慢,因为对索引中包含的字段的每次插入/更新也需要插入/更新索引
根据您发布的解释结果,集合中至少有以下索引:
_p_pais_-1__p_user_-1__created_at_-1
languageCodeTatoeba_1_lowercase_1
languageCodeTatoeba_1
languageCodeTatoeba_-1
_p_pais_-1
_p_pais_1_languageCodeTatoeba_1
palabra_-1
palabra_1__created_at_-1
这组索引有两个问题:
在这些索引中,有些是冗余的。例如,languageCodeTatoeba_1
(升序索引)和languageCodeTatoeba_-1
(降序索引)实际上是相同的索引。可以删除其中一个,而不会对查询性能产生任何影响
许多索引是另一个索引的前缀。例如,palabra_uu-1
和palabra_u-1在
创建。可以删除palabra_uu1
索引,因为它是在
索引处创建的palabra_1_uu的前缀。请参阅该页了解更多详细信息
粗略地看一下,您可以将索引列表调整为仅包含以下4个索引,而不是8个:
_p_pais_-1__p_user_-1__created_at_-1
languageCodeTatoeba_1_lowercase_1
_p_pais_1_languageCodeTatoeba_1
palabra_1__created_at_-1
有关索引的更多信息,请参阅以下链接:
3。为什么从$或术语中删除一个子句会加快查询速度
这是因为查询
{"palabra": {...}, $or: [{"_p_pais": {...}}]}
本质上与
{"palabra": {...}, "_p_pais": {...}}
{"palabra": {...}, "languageCodeTatoeba": {...}}
假设您有一个复合索引,例如palabra_1_p_pais_1
,MongoDB将能够使用该索引
同样地
{"palabra": {...}, $or: [{"languageCodeTatoeba": {...}}]}
本质上与
{"palabra": {...}, "_p_pais": {...}}
{"palabra": {...}, "languageCodeTatoeba": {...}}
此查询可以使用集合中已有的\u p\u pais\u 1\u languageCodeTatoeba\u 1
索引
简而言之,这两个查询很快,因为您删除了$或子句,使MongoDB能够使用正确的索引。您可以发布快速查询的.explain()
?