MongoDB 基础系列十八:索引之管理

前言

此篇博文是 Mongdb 基础系列之一;

本文为作者的原创作品,转载需注明出处;

增、删、查、改

查看 indexes

查看一个 Collection 上的所有的索引

假设我们有 people collection,

1
db.people.getIndexes()

查看一个 Database 中所有的索引

可以通过如下的方式进行查询;

1
2
3
4
5
db.getCollectionNames().forEach(function(collection) {
indexes = db[collection].getIndexes();
print("Indexes for " + collection + ":");
printjson(indexes);
});

删除 indexes

删除一个特定的 index

1
db.accounts.dropIndex( { "tax-id": 1 } )

返回

1
{ "nIndexesWas" : 3, "ok" : 1 }

删除所有 index

直接在某一个 collection 上使用方法 dropIndexes() 即可

1
db.collection.dropIndexes()

该命令不会将 _id 索引给删除了;

修改 index

想要修改该某一个 index,除了 TTL index,必须对该 index 进行先 drop 然后在重新创建的方式;

使用 reindex() 全部重建

使用 db.collection.reindex() 方法来重建索引,它会先删除该 collection 上的所有的 indexs,注意包含 _id 索引字段,然后再全部进行重建;该方法的调用不接受任何的参数,

1
db.collection.reIndex()

手动删除再创建

如果误创建了一个索引,索引的条件不是自己期望的;那么只能先删除该索引,然后通过索引创建命令,重新输入索引条件并重新创建;

测量和检测索引

查看索引的使用情况

通过 aggregation stage 操作 $indexStats 来获取当前 collection 的索引被使用的统计信息;

假设我们有如下的 orders 的数据,

1
2
3
{ "_id" : 1, "item" : "abc", "price" : 12, "quantity" : 2, "type": "apparel" }
{ "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "type": "electronics" }
{ "_id" : 3, "item" : "abc", "price" : 10, "quantity" : 5, "type": "apparel" }

对该 collection 我们创建了两个索引

1
2
db.orders.createIndex( { item: 1, quantity: 1 } )
db.orders.createIndex( { type: 1, item: 1 } )

在该 collection 上执行两次查询

1
2
db.orders.find( { type: "apparel"} )
db.orders.find( { item: "abc" } ).sort( { quantity: 1 } )

OK,下面我们来看一下索引使用的情况,

1
db.orders.aggregate( [ { $indexStats: { } } ] )

返回,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
"name" : "item_1_quantity_1",
"key" : {
"item" : 1,
"quantity" : 1
},
"host" : "examplehost.local:27017",
"accesses" : {
"ops" : NumberLong(1),
"since" : ISODate("2015-10-02T14:31:53.685Z")
}
}
{
"name" : "_id_",
"key" : {
"_id" : 1
},
"host" : "examplehost.local:27017",
"accesses" : {
"ops" : NumberLong(0),
"since" : ISODate("2015-10-02T14:31:32.479Z")
}
}
{
"name" : "type_1_item_1",
"key" : {
"type" : 1,
"item" : 1
},
"host" : "examplehost.local:27017",
"accesses" : {
"ops" : NumberLong(1),
"since" : ISODate("2015-10-02T14:31:58.321Z")
}
}

可见,返回了一系列的 documents,那么我们该如何来读该返回的结果记录呢?

字段 描述
name index 的名字
key index key 的说明,通过 1 和 0 来表示是升序还是降序
host 在那台主机和哪个端口上使用到了该索引
acesses 返回该索引字段被使用到的记录信息
+ ops 被使用到的次数;
+ since 该索引的统计信息是在什么时候开始统计的

由此,我们来看一下某个索引的使用情况

1
2
3
4
5
6
7
8
9
10
11
12
{
"name" : "type_1_item_1",
"key" : {
"type" : 1,
"item" : 1
},
"host" : "examplehost.local:27017",
"accesses" : {
"ops" : NumberLong(1),
"since" : ISODate("2015-10-02T14:31:58.321Z")
}
}

很明显,该索引是对 { type: 1, item: 1 } 索引的使用情况的统计记录,在 local server 的端口 27017 上被使用,从 2015-10-02T14:31:58.321Z 开始,总共被使用了 1 次;

Query Plan

Use the db.collection.explain() or the cursor.explain() method in executionStats mode to return statistics about the query process, including the index used, the number of documents scanned, and the time the query takes to process in milliseconds.

Run db.collection.explain() or the cursor.explain() method in allPlansExecution mode to view partial execution statistics collected during plan selection.

db.collection.explain() provides information on the execution of other operations, such as db.collection.update(). See db.collection.explain() for details.

hint() 强制 find() 使用某索引

使用 hint() 方法可以强制 db.collection.find() 使用某个索引;比如,

1
2
3
db.people.find(
{ name: "John Doe", zipcode: { $gt: "63000" } }
).hint( { zipcode: 1 } )

可以使用下面的两种方式来检查索引被使用的状态,

  1. 在 hint() 方法之后使用 explain()

    1
    2
    3
    db.people.find(
    { name: "John Doe", zipcode: { $gt: "63000" } }
    ).hint( { zipcode: 1 } ).explain("executionStats")
  2. 或者在 find() 之后使用 hint() 也可以

    1
    2
    3
    db.people.explain("executionStats").find(
    { name: "John Doe", zipcode: { $gt: "63000" } }
    ).hint( { zipcode: 1 } )

使用 hint() 方法,通过指定 $natural 操作符,也可以强制 MongoDB 不使用任何索引;

1
2
3
db.people.find(
{ name: "John Doe", zipcode: { $gt: "63000" } }
).hint( { $natural: 1 } )

index 的使用报告