2

我正在运行一个非常普通的 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假的,我该如何优化这个查询/索引?

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

4

1 回答 1

7

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

它不是。它正在通过索引:

"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”,其值为 true 或 false。在 (art_filter, idIsHauptArtikelNr) 上创建一个索引,并将您的查询替换为

  { art_filter :{ $exists :false}, idIsHauptArtikelNr : true }
于 2012-04-11T12:34:00.447 回答