【问题标题】:Why would this mongo query be so slow?为什么这个 mongo 查询会这么慢?
【发布时间】:2015-07-11 17:20:47
【问题描述】:

我正试图弄清楚如何处理这种情况。最终应该是日期范围。

db.article_raw.count({
   "date": {$gt:ISODate("2015-07-08T00:00:00.000Z")},
   "searchTerms.term":"iPhone"
})

我有以下 3 个索引(我知道它们是重复的,但我正在努力弄清楚)

{
   "date" : 1,
   "searchTerms.term" : 1
}

{
    "date" : 1
}

{
    "searchTerms.term" : 1
}

数据看起来像

{
    title: "a cool title",
    date: ISODate("2015-07-09T11:58:36.000Z"),
    "searchTerms" : [ 
        {
            "term" : "According to Jim",
            "relevance" : "0.315"
        }, 
        {
            "term" : "iPhone",
            "relevance" : "0.057"
        }
   }
}

最后,这是 find() 版本的 explain() 的结果。

{
    "cursor" : "BtreeCursor date & search",
    "isMultiKey" : true,
    "n" : 275,
    "nscannedObjects" : 275,
    "nscanned" : 11022,
    "nscannedObjectsAllPlans" : 16142,
    "nscannedAllPlans" : 26889,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 1074,
    "nChunkSkips" : 0,
    "millis" : 59548,
    "indexBounds" : {
        "date" : [ 
            [ 
                ISODate("2015-07-08T00:00:00.000Z"), 
                Date(9223372036854775807)
            ]
        ],
        "searchTerms.term" : [ 
            [ 
                "iPhone", 
                "iPhone"
            ]
        ]
    },
    "server" : "...",
    "filterSet" : false,
    "stats" : {
        "type" : "FETCH",
        "works" : 11023,
        "yields" : 1074,
        "unyields" : 1074,
        "invalidates" : 90,
        "advanced" : 275,
        "needTime" : 10746,
        "needFetch" : 1,
        "isEOF" : 1,
        "alreadyHasObj" : 0,
        "forcedFetches" : 0,
        "matchTested" : 0,
        "children" : [ 
            {
                "type" : "IXSCAN",
                "works" : 11022,
                "yields" : 1074,
                "unyields" : 1074,
                "invalidates" : 90,
                "advanced" : 275,
                "needTime" : 10746,
                "needFetch" : 0,
                "isEOF" : 1,
                "keyPattern" : "{ date: 1, searchTerms.term: 1 }",
                "isMultiKey" : 1,
                "boundsVerbose" : "field #0['date']: (new Date(1436313600000), new Date(9223372036854775807)], field #1['searchTerms.term']: [\"iPhone\", \"iPhone\"]",
                "yieldMovedCursor" : 0,
                "dupsTested" : 275,
                "dupsDropped" : 0,
                "seenInvalidated" : 0,
                "matchTested" : 0,
                "keysExamined" : 11022,
                "children" : []
            }
        ]
    }
}

如果这些索引是正确的,我看不出这个查询需要 80 秒才能运行。系统中有近百万篇文章。这个计数的结果大约是 250。

【问题讨论】:

  • 您应该考虑使用[searchTerms.term, date] 索引;在范围匹配之前执行精确匹配总是更好的选择。
  • 你能提供 .explain(true) 的结果吗?
  • 机器有多少内存,你用的是什么版本的mongo。
  • 你通过performance tuning了吗?
  • @ChrisHeald 这不是正在发生的事情吗?

标签: javascript performance mongodb optimization mongodb-query


【解决方案1】:

这似乎是 Sean 在大型数据集中的预期行为,由于高基数,索引是在日期创建的。 MongoDB 现在使用 B(alance)-Tree 索引,如果列值具有数百万个不同的值(因为日期精确到毫秒,并且它们中的大多数不一样的可能性很大),那么最终尽管它使用索引它没有提供任何好处在这种情况下的索引。 通常在这种情况下,您必须根据某个日期范围查找数据,最好再多一列,其中仅包含您应用索引的日期部分并在查询条件中使用它,这可能有助于显着提高您的性能..

-$

【讨论】:

  • 即使对于 $gt 这样的日期范围仍然适用?
  • 是的,在任何类型的条件下检查它必须旅行并决定去哪个节点......我的意思是,在 $gt 条件下,日期索引也被使用,正如解释所建议的那样计划但由于基数高而无用。散列索引是唯一用于相等性检查并在范围检查时被忽略的索引,因为它们依赖于散列。
  • 另外,现在我看到所有 cmets..Chris solition 是完美的,索引的顺序非常重要,在你的情况下,它会首先尝试匹配由于高基数而缓慢的日期,并且然后是术语,但是如果你颠倒顺序,那么首先它会立即找到术语 iPhone,然后在那些有限的数据集中,它会检查日期条件,这肯定会比你最初做的更快......我仍然建议仅通过额外的日期部分 n 在术语:1,日期部分:1 中创建一个索引,这样做会使您在更大的数据集中的搜索速度更快,比较您当前的一个
猜你喜欢
  • 2011-10-18
  • 2011-03-11
  • 2020-03-19
  • 2014-03-12
  • 2011-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-06
相关资源
最近更新 更多