使用$或运算符时,MongoDB查询会变慢

时间:2017-02-19 16:32:13

标签: mongodb indexing mongodb-query

我正在尝试将此查询发送到我的收藏集import csv import re f = open('my_file_path') csv_f = csv.reader(f) b = csv_f.replace(' ', '') print b f.close() - Is the above syntax correct, still getting an error. hmm

Audios

实际上确实非常慢,但如果删除任何 var querySlow = { "palabra": { $regex: "^" + keywords, "$options": "i" }, $or: [{ "_p_pais": { $in: interested_accents } }, { "languageCodeTatoeba": { $in: interested_accents_tatoeba } }] }; // takes 20 seconds ,则非常快,例如:

$or

或者

    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

http://pastebin.com/nrhjB1wf

我实际上不知道如何管理索引,我应该为这个集合创建索引吗?

1 个答案:

答案 0 :(得分:1)

您的查询和索引存在一些问题:

<强> 1。 $或以不同方式使用索引

MongoDB仅为查询使用一个索引,但涉及$or子句的查询除外。来自Indexing Strategies页面:

  

通常,MongoDB只使用一个索引来完成大多数查询。但是,$或查询的每个子句都可以使用不同的索引

同样来自$or Clauses and Indexes页面:

  

也就是说,对于MongoDB使用索引来计算$或表达式,$或表达式中的所有子句必须由索引支持。

关于您的查询,您可以尝试重新排列查询以使$or子句成为顶级子句:

{$or: [
    {"palabra": {...}, "_p_pais": {...} },
    {"palabra": {...}, "languageCodeTatoeba": {...}}
]}

在这种形式中,MongoDB可以使用两个索引:

  • 包含palabra_p_pais字词的复合索引,以及
  • 包含palabralanguageCodeTatoeba条件的复合索引

请使用explain("executionStats")检查索引是否正确使用。要最小化的关键指标是文档数量(nReturned)与检查的文档/密钥总数。比率越接近1,查询的选择性就越高,性能就越好。

例如,如果MongoDB必须检查1000个文档(totalDocsExamined: 1000),但只返回10个文档(nReturned: 10),那么您的查询不是很有选择性(即比率为10/1000) 。理想的查询将具有接近或等于1的比率,例如, nReturned: 10, totalDocsExamined: 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

这组索引存在两个问题:

  1. 在索引中,有些是多余的。例如,languageCodeTatoeba_1(升序索引)和languageCodeTatoeba_-1(降序索引)实际上是相同的索引。可以删除其中一个而不会影响查询性能。
  2. 很多索引都是另一个索引的前缀。例如,palabra_-1palabra_1__created_at_。可以删除palabra_-1索引,因为它是palabra_1__created_at_索引的前缀。有关详细信息,请参阅Compound Index: Prefix页面。
  3. 从粗略的一瞥,您可以修剪索引列表,只包含这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。为什么从$or术语中删除一个子句会加快查询速度

    这是因为查询

    {"palabra": {...}, $or: [{"_p_pais": {...}}]}
    

    基本相同
    {"palabra": {...}, "_p_pais": {...}}
    

    假设您有一个复合索引,例如palabra_1__p_pais_1,MongoDB将能够使用该索引。

    类似地,

    {"palabra": {...}, $or: [{"languageCodeTatoeba": {...}}]}
    

    基本相同
    {"palabra": {...}, "languageCodeTatoeba": {...}}
    

    此查询可以使用您在集合中已有的_p_pais_1_languageCodeTatoeba_1索引。

    简而言之,这两个查询很快,因为您删除了$or子句,使MongoDB能够使用正确的索引。