mongodb基础篇--索引


mongodb使用索引可以提高查询效率。如果没有索引,mongodb会进行全文检索。
MongoDB索引的数据结构是B-tree。
MongoDB 提供了非常多的索引类型来支持特定类型的数据和查询,例如单字段索引、复合索引、多键索引、文字索引、2d 索引、散列索引和稀疏索引等。

索引创建

单字段索引

创建索引的语法格式如下:

db.collection.createIndex( <key and index type specification>, <options> )

示例(添加user_id索引):

db.getCollection('test').createIndex({"user_id":1})

返回值:

{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 5,
    "numIndexesAfter" : 6,
    "ok" : 1.0,
    "operationTime" : Timestamp(1575635741, 1)
}

numIndexesBefore 表示本次索引创建前的索引数量
numIndexesAfter 表示本次索引创建后的索引数量
mongoDB 有为每个集合创建了默认的索引,默认索引的字段为 _id

我们可以通过执行计划对比查看效率是否提升。

db.getCollection('test').find({"user_id":-1}).explain("executionStats")

再返回结果的stage中:
建立索引前为COLLSCAN,即扫描整个集合:

 "stage" : "COLLSCAN"

建立索引后为IXSCAN,即按索引检索文档:

 "stage" : "IXSCAN"

我们除了可以为指定字段设置索引,还可以为内嵌文档的字段建立索引。

比如有如下文档结构:

{
    "_id" : 1,
    "citys" : [ 
        {

            "city_id" : 380810,
            "city_name" : "布列塔尼半岛"
        }
    ],
    "user_id":-1
}

为内嵌文档citys添加索引:

db.getCollection('test').createIndex({"citys":1})

为了内嵌文档citys中的city_id添加索引:

db.getCollection('test').createIndex({"citys.city_id":1})

其中:1为正序,-1为倒序。

对于单字段索引来说,索引键的排序顺序并不重要。

复合索引

单字段索引并不能满足所有需求,有时候我们需要为文档建立更多的索引,多个字段的组合索引在 MongoDB 中称为复合索引。创建复合索引的语法格式如下:

db.collection.createIndex( { <field1>: <type>, <field2>: <type2>, ... } )

注意:索引键的排序顺序(即升序或降序)在复合索引中是非常重要的,它可以确定索引是否支持排序操作

准备以下数据:

db.getCollection('test').insertMany([
{_id: 1, name: "James", number: 6, h: 203, w: 222},
{_id: 2, name: "Wade", number: 3, h: 193, w: 220},
{_id: 3, name: "Kobe", number: 24, h: 198, w: 212},
{_id: 4, name: "Yao", number: 11, h: 226, w: 308},
{_id: 5, name: "Jd", number: 23, h: 198, w: 216}
])

然后为身高和体重这两个字段创建索引。其中,身高索引为升序,体重索引为降序。对应示例如下:

db.getCollection('test').createIndex({h:1,w:-1})

返回结果:

{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1.0,
    "operationTime" : Timestamp(1575709525, 2)
}

我们查询后按照身高升序,体重降序:

db.getCollection('test').find().sort({h:1,w:-1})

返回结果是正确的;

然后按照身高升序,体重也升序:

db.getCollection('test').find().sort({h:1,w:1})

返回结果也是符合预期的。

但是sort({h:1,w:-1})的执行计划:

"stage" : "IXSCAN"

sort({h:1,w:1})的执行计划:

 "stage" : "COLLSCAN"

这说明如果索引支持查询时所用的排序规则,那么索引将会发挥作用。如果不支持,索引不会发挥作用。

索引前缀

索引前缀(也有人称前缀索引)是索引字段的起始子集。假设有以下复合索引:

{ "number": 1, "h": 1, "w": 1 }

该复合索引的索引前缀为:

{ number: 1 }
{ number: 1, h: 1 }

MongoDB 允许我们在以下字段中使用索引进行查询:

  • number 字段
  • number 字段和 h 字段
  • number 字段、h字段和 w字段

这是因为查询时使用 number 或 number & h 组合作为索引前缀。如果使用其他索引前缀, 那就无法使用索引。

也就是说,使用类似 db.indx.find({h: 1, w: 1, number: 1}) 这样的语句时,stage 的值为 IXSCAN,即索引起作用。

当使用类似 db.indx.find({h: 1, w: 1}) 这样的查询语句时,stage 的值为 COLLSCAN,索引不起作用。

多键索引

在创建索引时,如果设定的字段值是数组,那么 MongoDB 就会为数组中的每一个元素创建索引键。多键索引的创建是完全自动的,不需要显式指定。准备以下数据:

db.getCollection('test').insertMany([
{ _id: 6, type: "food", item: "bbb", ratings: [ 5, 9 ] },
{ _id: 7, type: "food", item: "ccc", ratings: [ 9, 5, 8 ] },
{ _id: 8, type: "food", item: "ddd", ratings: [ 9, 5 ] },
{ _id: 9, type: "food", item: "eee", ratings: [ 5, 9, 5 ] },
{ _id: 10, type: "food", item: "aaa", ratings: [ 5, 8, 9 ] }
])

为ratings创建索引:

db.getCollection('test').createIndex({ratings:1})

由于 ratings 字段的值是数组,所以这个索引并不是单字段索引,而是多键索引。

比如如下查询:

db.getCollection('test').find({"ratings":[5,9]})

执行计划:

db.getCollection('test').find({"ratings":[5,9]}).explain("executionStats")

返回stage:

"stage" : "IXSCAN"

注意:MongoDB 不允许创建超过 1 个数组的复合多键索引。

查看索引

查看索引:

db.collection.getIndexes()

比如:

db.getCollection('test').getIndexes()

返回值:

[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "w.test"
    },
    {
        "v" : 2,
        "key" : {
            "h" : 1.0,
            "w" : -1.0
        },
        "name" : "h_1_w_-1",
        "ns" : "w.test"
    },
    {
        "v" : 2,
        "key" : {
            "ratings" : 1.0
        },
        "name" : "ratings_1",
        "ns" : "w.test"
    }
]
  • name 表示索引名称
  • key 表示索引键
  • ns 表示集合名称

索引的命名

默认情况下,索引的名称是字段与排序的组合词,例如复合多键索引 {item: 1, ratings: -1} 的索引名称为 item_1_ratings_-1。

当然,我们也可以在创建索引的时候指定索引名称,对应示例如下:

db.getCollection('test').createIndex( {item: 1,  ratings: -1 }, {name: "idx_item_rate"} )

执行后,索引就多个名为idx_item_rate的复合索引:

{
    "v" : 2,
    "key" : {
        "item" : 1.0,
        "ratings" : -1.0
    },
    "name" : "idx_item_rate",
    "ns" : "w.test"
}

索引删除

删除方法为:

db.collection.dropIndex(index_name)

删除指定索引,比如删除idx_item_rate:

db.collection.dropIndex("idx_item_rate")

返回结果:

{
    "nIndexesWas" : 4,
    "ok" : 1.0,
    "operationTime" : Timestamp(1575711769, 1)
}

删除所有索引:

db.collection.dropIndexes()

返回结果如下:

{
    "nIndexesWas" : 3,
    "msg" : "non-_id indexes dropped for collection",
    "ok" : 1.0,
    "operationTime" : Timestamp(1575712069, 2)
}

默认索引 _id 不会被删除。

索引能够提高查询效率,但是也不能盲目加索引,因为在文档的新增和编辑时会维护索引。索引太多,会加大维护成本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值