以下哪个查询将使用索引?

Which of the following queries will use the index?

给定集合 foo 具有以下索引:

db.foo.createIndex( { a : 1, b : 1, c : 1 } )

我们需要select以下哪些查询将使用索引?

  1. db.foo.find( { c : 1 } ).sort( { a : -1, b : 1 } )
  2. db.foo.find( { b : 3, c : 4 } )
  3. db.foo.find( { a : 3 } )
  4. db.foo.find( { c : 1 } ).sort( { a : 1, b : 1 } )

我很惊讶 34 是正确的选项,12 不是。

为什么下面的查询会用到索引?

db.foo.find( { a : 3 } )

这似乎可以使用索引但是_id没有投影出来。

db.foo.find( { c : 1 } ).sort( { a : 1, b : 1 } )

我们正在寻找位于索引右侧c

为什么下面的查询会"not"使用索引?

db.foo.find( { c : 1 } ).sort( { a : -1, b : 1 } )

db.foo.find( { b : 3, c : 4 } )

关于第一个问题:db.foo.find( { c : 1 } ).sort( { a : -1, b : 1 } )

方向很重要,这里有更多信息 why does direction of index matter in MongoDB?.

你可以看看 http://openmymind.net/mongodb.pdf => 第 56 页

关于第二个。索引中定义的键的顺序也很重要。 这里有更多信息 =>

查询 1

db.foo.find( { c: 1 } ).sort( { a: -1, b: 1 } );

使用 { c: 1 } 过滤将不会使用索引,因为 { c: 1 } 不是 { a: 1, b: 1, c: 1 } (documentation). Sorting with { a: -1, b: 1 } will not use the index, since sort direction (1 or -1) does matter (documentation) 的前缀。

查询 2

db.foo.find( { b: 3, c: 4 } );

使用 { b: 3, c: 4 } 过滤将不会使用索引,因为 { b: 1, c: 1 } 不是 { a: 1, b: 1, c: 1 } 的前缀。

查询 3

db.foo.find( { a: 3 } );

使用 { a: 3 } 过滤将使用索引,因为 { a: 1 }{ a: 1, b: 1, c: 1 } 的前缀。

This seems to be able to use the index however _id is not projected out.

字段 _id 将在查询结果中,除非您指定相反。

对于文档 { _id: 1, a: 3, b: 4, c: 5 } 考虑下一个查询及其结果

> db.foo.find( { a: 3 }, { _id: 0, a: 1, b: 1, c: 1 } );
{ "a": 3, "b": 4, "c": 5 }
> db.foo.find( { a: 3 }, { a: 1 } ).explain("executionStats");
...
"executionStats": {
    "totalKeysExamined" : 1,
    "totalDocsExamined" : 0,
    ...
> db.foo.find( { a: 3 } );
{ "_id": 0, "a": 3, "b": 4, "c": 5 }
> db.foo.find( { a: 3 } ).explain("executionStats");
...
"executionStats": {
    "totalKeysExamined": 1,
    "totalDocsExamined": 1,
    ...

请注意,在第二种情况下,文档的 _id 是在索引扫描后从集合 ("totalDocsExamined": 1) 中提取的,因为查询并未说明 _id 字段不是必需的结果。

查询 4

db.foo.find( { c: 1 } ).sort( { a: 1, b: 1 } );

使用 { a: 1, b: 1 } 排序将使用索引,因为 { a: 1, b: 1 }{ a: 1, b: 1, c: 1 } 的前缀子集(对于非前缀子集 - 请参阅 documentation) and sort keys are listed in the same order, direction as in the { a: 1, b: 1, c: 1 } (documentation)。但是,索引不会用于过滤,因为 { c: 1 } 不是 { a: 1, b: 1, c: 1 } 的前缀。考虑下一个查询及其结果

> db.foo.find( { c: 1 }, { _id: 0 } ).sort( { a: 1, b: 1 } ).explain("executionStats");
...
"executionStages": {
    "stage": "FETCH",
    "filter": {
        "c": { "$eq": 3 } // filtering is done by fetching from the collection
    },
    "inputStage": {
        "stage": "IXSCAN",
        "indexBounds": {
            "a": [ "[MINKEY, MAXKEY]" ],
            "b": [ "[MINKEY, MAXKEY]" ],
            "c": [ "[MINKEY, MAXKEY]" ] // index was not used for filtering c
        }
        ...
> db.foo.find( { a: 1 }, { _id: 0 } ).sort( { a: 1, b: 1 } ).explain("executionStats");
...
"executionStages": {
    "stage": "PROJECTION",
    "inputStage": {
        "stage": "IXSCAN",
        "indexBounds": {
            "a": [ "[3.0, 3.0]" ],      // index was used for filtering a
            "b": [ "[MINKEY, MAXKEY]" ],
            "c": [ "[MINKEY, MAXKEY]" ]
        }
        ...

请注意,在第二种情况下,过滤和排序都是使用索引完成的,并且没有调用集合。