【问题标题】:Optimize MongoDB Query or Index优化 MongoDB 查询或索引
【发布时间】:2012-04-11 12:21:56
【问题描述】:

我正在运行一个非常普通的 MongoDB 查询,没有什么复杂或特别的,我想知道它所花费的时间(> 1 秒)是否正常,或者我的索引是否有问题。

我为此特定查询提供了一个索引,explain() 也告诉我它已被使用,但它每次都会对集合进行全面扫描,并使整个网页的速度减慢 > 1 秒。

查询:

db.tog_artikel.find({"art_filter":{"$exists":false},"$where":"this._id == this.art_hauptartikelnr"})

解释:

> db.tog_artikel.find({"art_filter":{"$exists":false},"$where":"this._id == this.art_hauptartikelnr"}).explain()
{
    "cursor" : "BtreeCursor art_filter_1_art_hauptartikelnr_1",
    "nscanned" : 21306,
    "nscannedObjects" : 21306,
    "n" : 21306,
    "millis" : 1180,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : false,
    "indexOnly" : false,
    "indexBounds" : {
        "art_filter" : [
            [
                null,
                null
            ]
        ],
        "art_hauptartikelnr" : [
            [
                {
                    "$minElement" : 1
                },
                {
                    "$maxElement" : 1
                }
            ]
        ]
    }
}

索引:

{
   "v": 1,
   "key": {
     "art_filter": 1,
     "art_hauptartikelnr": 1 
  },
   "ns": "togshop.tog_artikel",
   "background": true,
   "name": "art_filter_1_art_hauptartikelnr_1" 
}

为什么每次都扫描完整的集合?为什么isMultiKey 是假的,我该如何优化这个查询/索引?

Environment 是一个独立的服务器,MongoDB 2.0.1,64 位 Linux,从带有 php-mongo 1.2.6 的 PHP 访问

【问题讨论】:

    标签: optimization mongodb indexing


    【解决方案1】:

    为什么每次都扫描完整的集合?

    事实并非如此。它正在通过索引:

    "cursor" : "BtreeCursor art_filter_1_art_hauptartikelnr_1",
    

    这意味着索引“art_filter_1_art_hauptartikelnr_1”用于满足$exists条件。

    如果该过滤器的选择性不是很强(即有很多记录满足它),查询仍将花费大量时间。

    为什么 isMultiKey 是假的

    这是错误的,因为没有使用多键索引。多键索引是包含以数组作为值的字段的索引。它与复合索引(即具有多个字段)无关。

     $where":"this._id == this.art_hauptartikelnr"
    

    您的第二个条件是 Javascript 表达式,此处不能使用索引(因为查询分析器不了解您在做什么)。 即使有,您也需要一个包含 _id 的索引。

    如何优化这个查询/索引?

    对您的数据进行非规范化处理,使其具有一个新字段“idIsHauptArtikelNr”,其值为真或假。 在 (art_filter, idIsHauptArtikelNr) 上创建一个索引,并将您的查询替换为

      { art_filter :{ $exists :false}, idIsHauptArtikelNr : true }
    

    【讨论】:

    • 我要补充一点,尽管 $exists 现在确实使用了索引,但它仍然需要遍历大部分 b-tree 才能满足它。换句话说,就性能而言,您设法在一个查询中使用了两个最差的操作($exists 和 $where)。
    • @RemonvanVliet:我正要提到这一点,但后来我认为 $exists:false 在非稀疏索引上应该相对有效(而 $exists:true 确实必须走大部分那个树)。 YMMV 取决于数据偏差。
    • 非常正确。 $exists:false 是更有效的方法,因为在树中行走较早。无论如何,如果可以的话,通常最好避免 $exists 并且几乎总是 $where ;)
    • 非常感谢您的有益反应! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    • 1970-01-01
    • 2015-01-21
    • 2015-01-09
    相关资源
    最近更新 更多