优化MongoDB查询或索引

pro*_*mus 2 indexing optimization mongodb

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

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

查询:

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

解释:

> 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
                }
            ]
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

指数:

{
   "v": 1,
   "key": {
     "art_filter": 1,
     "art_hauptartikelnr": 1 
  },
   "ns": "togshop.tog_artikel",
   "background": true,
   "name": "art_filter_1_art_hauptartikelnr_1" 
}
Run Code Online (Sandbox Code Playgroud)

为什么每次都要扫描整个集合?为什么是isMultiKeyfalse,我如何优化此查询/索引?

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

Thi*_*ilo 7

为什么每次都要扫描整个集合?

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

"cursor" : "BtreeCursor art_filter_1_art_hauptartikelnr_1",
Run Code Online (Sandbox Code Playgroud)

这意味着索引"art_filter_1_art_hauptartikelnr_1"用于满足$ exists条件.

如果该过滤器不是非常有选择性(即有许多记录满足它),则查询仍将花费大量时间.

为什么isMultiKey为false

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

 $where":"this._id == this.art_hauptartikelnr"
Run Code Online (Sandbox Code Playgroud)

您的第二个条件是Javascript表达式,并且此处不能使用索引(因为查询分析器无法理解您正在执行的操作).即使它确实如此,您也需要一个也包含_id的索引.

如何优化此查询/索引?

对数据进行非规范化,使其具有值为true或false的新字段"idIsHauptArtikelNr".在(art_filter,idIsHauptArtikelNr)上创建索引,并用.替换您的查询

  { art_filter :{ $exists :false}, idIsHauptArtikelNr : true }
Run Code Online (Sandbox Code Playgroud)

  • 我将补充说,虽然$ exists确实使用索引,但它仍然需要走大部分b树来满足它.换句话说,就性能而言,您在一个查询中设法使用了两个最差的操作($ exists和$ where). (2认同)
  • @RemonvanVliet:我当然要提到这一点,但后来我认为$存在:false应该在非稀疏索引上相对有效(而$ exists:true确实必须遍历树的大部分).YMMV取决于数据偏差. (2认同)