MongoDB索引属性介绍

本文涉及的产品
云数据库 MongoDB,通用型 2核4GB
简介: 本文主要介绍了一下MongoDB索引的几个索引属性。

一、TTL索引

1、语法

db.eventlog.createIndex( { "lastModifiedDate": 1 }, { expireAfterSeconds: 3600 } )

2、TTL索引的功效

   TTL索引会根据TTL索引字段在一定的时间限制后自动删除过期文档,TTL索引更多的适用于只需要保存有限时间的集合,如机器生成的事件信息、日志、会话信息等。

3、expireAfterSeconds

1)expireAfterSeconds>0

   表示TTL索引字段超过expireAfterSeconds值后会自动被删除

> db.eventlog.createIndex( { "lastModifiedDate": 1 }, { expireAfterSeconds: 60 } )
> 
> db.eventlog.find()
{ "_id" : ObjectId("5d33e28c61f53a0e4ef75a45") }
{ "_id" : ObjectId("5d33e28c61f53a0e4ef75a46") }
{ "_id" : ObjectId("5d33e28e61f53a0e4ef75a47") }
{ "_id" : ObjectId("5d33f1f261f53a0e4ef75a4c"), "lastModifiedDate" : ISODate("2019-07-21T05:02:42.287Z") }
{ "_id" : ObjectId("5d33f1f261f53a0e4ef75a4d"), "lastModifiedDate" : ISODate("2019-07-21T05:02:42.803Z") }
>
> db.eventlog.find()
{ "_id" : ObjectId("5d33e28c61f53a0e4ef75a45") }
{ "_id" : ObjectId("5d33e28c61f53a0e4ef75a46") }
{ "_id" : ObjectId("5d33e28e61f53a0e4ef75a47") }      
>
> new Date()
ISODate("2019-07-21T05:04:51.005Z")        //可以看到即使expireAfterSeconds设置为60s,也不是60s后立刻进行删除

2)expireAfterSeconds=0

   更多的用在集合存在一个删除字段,如果该文档包括TTL索引字段,就会自动被MongoDB进行删除,如果该字段不高阔该索引字段,则不被删除

示例:

   对log_events集合的expireAt字段创建expireAfterSeconds: 0的TTL索引,当expireAt字段不存在时,表示该文档永不删除,若需要删除某一文档,只需要将expireAt字段更新在该文档上即可。

db.log_events.createIndex( { "expireAt": 1 }, { expireAfterSeconds: 0 } )

> db.log_events.find()
{ "_id" : ObjectId("5d33e16861f53a0e4ef75a3c") }
{ "_id" : ObjectId("5d33e16961f53a0e4ef75a3d") }
{ "_id" : ObjectId("5d33e16961f53a0e4ef75a3e") }
{ "_id" : ObjectId("5d33e18661f53a0e4ef75a43"), "expireAt" : ISODate("2019-07-21T03:52:38.212Z") }
{ "_id" : ObjectId("5d33e18661f53a0e4ef75a44"), "expireAt" : ISODate("2019-07-21T03:52:38.682Z") }

//等待后台线程删除过期文档
> db.log_events.find()
{ "_id" : ObjectId("5d33e16861f53a0e4ef75a3c") }
{ "_id" : ObjectId("5d33e16961f53a0e4ef75a3d") }
{ "_id" : ObjectId("5d33e16961f53a0e4ef75a3e") }

4、如何定义过期数据

1)TTL索引字段超过expireAfterSeconds则被认为是过期文档

2)如果该字段为数组,且数组中由多个时间值,过期时间由最早的时间值决定

3)如果TTL索引字段不存在date或者包含date的数组,该文档永远不会过期

4)如果该索引字段不存在,则该文档永远不会删除

5、TTL索引如何进行删除操作

1)由一个后台线程周期性查看TTL索引并删除过期数据(60s),该线程无法保证可以立刻删除过期的数据

2)TTL后台线程仅仅在副本集的主节点上进行删除,备份节点通过复制进行删除

6、TTL索引使用的一些限制

1)TTL索引不支持复合索引

2)_id字段不支持TTL索引

3)capped集合不支持创建TTL索引

4)若要改变expireAfterSeconds的值,必须删除重建索引

5)不能在相同的字段创建expireAfterSeconds不同的TTL索引

二、Unique索引

1、语法

db.collection.createIndex( <key and index type specification>, { unique: true } )

2、Unique索引一些特点

1)唯一索引主要是用来保证该索引列所有文档唯一不重复

2)每个集合的_id默认就是一个唯一索引,但是该唯一索引不可删除

3)在唯一索引字段,null具有唯一性,如果该索引字段已经存在一个null值,再次插入null值会冲突报错,若需要解决该问题可参考稀疏索引

示例:

> db.aa.find()
{ "_id" : ObjectId("5d2fee977737353186206a73"), "id" : 1 }
{ "_id" : ObjectId("5d2fee987737353186206a74"), "id" : 2 }
{ "_id" : ObjectId("5d2fee9b7737353186206a75"), "id" : 3 }
{ "_id" : ObjectId("5d2feea87737353186206a76") }
>
>
> db.aa.createIndex({id:1},{unique:true})
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}
> db.aa.insert({})
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 11000,
        "errmsg" : "E11000 duplicate key error collection: test.aa index: id_1 dup key: { : null }"
    }
})

三、Partial索引

1、语法

db.restaurants.createIndex(
   { cuisine: 1, name: 1 },
   { partialFilterExpression: { rating: { $gt: 5 } } }
)

partialFilterExpression可以指定不同的条件来做部分索引,主要类型如下:

    $exists: 是否存在 <=> 稀疏索引
    $gt, $gte, $lt, $lte :指定字段符合运算部分创建索引
    $type:
    $and:

2、Partial索引使用

索引可以当作普通索引来使用,但是在使用上存在一些限制,部分索引只要在符合partialFilterExpression条件的文档上创建索引,包含不符合部分文档的查询会使用COLLSCAN

1)创建索引如下

> db.restaurants.createIndex(
...    { cuisine: 1 },
...    { partialFilterExpression: { rating: { $gt: 5 } } }
... )

2)会使用索引的查询:

db.restaurants.find( { cuisine: "Italian", rating: { $gte: 8 } } )

3)不会使用索引的查询:

db.restaurants.find( { cuisine: "Italian", rating: { $lt: 8 } } )
db.restaurants.find( { cuisine: "Italian" } )

3、部分索引创建的一些限制

1)不可以在相同的字段创建两个不同的partialFilterExpression的部分索引

2)不可以同时使用partialFilterExpression和sparse

3)MongoDB3.2版本才开始支持

4)_id字段不支持使用部分索引

5)部分索引不可作为分片键

4、唯一部分索引

对于唯一部分索引,唯一性仅仅对符合partialFilterExpression部分文档满足

1)示例文档

> db.users.find()
{ "_id" : ObjectId("56424f1efa0358a27fa1f99a"), "username" : "david", "age" : 29 }
{ "_id" : ObjectId("56424f37fa0358a27fa1f99b"), "username" : "amanda", "age" : 35 }
{ "_id" : ObjectId("56424fe2fa0358a27fa1f99c"), "username" : "rajiv", "age" : 57 }

> db.users.createIndex(
...    { username: 1 },
...    { unique: true, partialFilterExpression: { age: { $gte: 21 } } }
... )

2)因唯一性冲突,插入报错

db.users.insert( { username: "david", age: 27 } )
db.users.insert( { username: "amanda", age: 25 } )
db.users.insert( { username: "rajiv", age: 32 } )

3)因不满足partialFilterExpression,不需要满足唯一性

db.users.insert( { username: "david", age: 20 } )
db.users.insert( { username: "amanda" } )
db.users.insert( { username: "rajiv", age: null } )

四、Case Insesitive索引

1、语法
db.collection.createIndex( 
{ "key" : 1 },
{ collation: {locale : <locale>,strength : <strength>}} )

collation:指定语言规则

strength:指定比较规则(是否区分大小写),1-5,数组越大,比较规则越严格,默认等级为3

2、Case Insesitive索引索引的一些特点

1)使用case insensitive索引会增加查询的资源消耗

2)在创建索引时指定locale和strength的话,查询时候需要指定相同的locale和strength才能确保有效使用索引。

示例集合

> db.fruit.find()
{ "_id" : ObjectId("5d2af3815e1bc81c62ef58b6"), "type" : "apple" }
{ "_id" : ObjectId("5d2af3815e1bc81c62ef58b7"), "type" : "Apple" }
{ "_id" : ObjectId("5d2af3815e1bc81c62ef58b8"), "type" : "APPLE" }

db.fruit.createIndex( { type: 1},
{ collation: { locale: 'en', strength: 2 } } )

查询结果

1.没有指定locale和strength,无法使用索引,查询记录为1
db.fruit.find( { type: "apple" } ) 

2.指定索引对应的locale和strength,使用索引,查询记录为2
db.fruit.find( { type: "apple" } ).collation( { locale: 'en', strength: 2 } )

3.指定非索引对应的locale和strength,不使用索引,返回记录为1
db.fruit.find( { type: "apple" } ).collation( { locale: 'en', strength: 1 } )

3)当创建集合时指定了locale和strength,集合的索引和查询默认使用对应的locale和strength,不需要特别指定。

示例集合

> db.createCollection("names", { collation: { locale: 'en_US', strength: 2 } } )
> db.names.createIndex( { first_name: 1 } ) // inherits the default collation
> db.names.find()
{ "_id" : ObjectId("5d3023b1cd8afaa592e2398d"), "first_name" : "Betsy" }
{ "_id" : ObjectId("5d3023b1cd8afaa592e2398e"), "first_name" : "BETSY" }
{ "_id" : ObjectId("5d3023b1cd8afaa592e2398f"), "first_name" : "betsy" }

查询结果

1.使用集合默认locale和strength,返回记录为3
db.names.find( { first_name: "betsy" } )

2.无法使用索引且只返回一条记录,因为strength默认为3
db.names.find( { first_name: "betsy" } ).collation( { locale: 'en_US' } )

五、Sparse索引

1、语法

db.addresses.createIndex( { "xmpp_id": 1 }, { sparse: true } )

2、稀疏索引的一些特点

1)稀疏索引的索引仅仅会覆盖包含索引字段的文档,所以根据稀疏索引来统计文档数/查询/排序时,可能得到的计算往往不是准确的

示例集合

> db.collection.find()
{ "_id" : 1, "y" : 1 }
{ "_id" : 2, "x" : 1, "y" : 2 }
{ "_id" : 3, "x" : 2 }

db.collection.createIndex( { x: 1 }, { sparse: true } );
db.collection.createIndex({ y: 1 });

查询结果

> db.collection.find().count();
3
> db.collection.find().hint({ y: 1 }).count();
3
> db.collection.find().hint( { x: 1 } ).count();        //仅统计x字段存在的记录
2

2)2dsphere (version 2)、 2d,、geoHaystack、text indexes都默认为稀疏索引

3)2dsphere和text都可以创建为稀疏复合索引,这些稀疏复合索引是否存在仅仅依赖于geospatial/text索引字段

3、稀疏索引的查询

1)示例文档

> db.scores.find()
{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
> db.scores.createIndex( { score: 1 } , { sparse: true } )

2)查询结果

#查询结果不会包含无score字段记录
> db.scores.find( { score: { $lt: 90 } } )
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }

4、稀疏索引的排序

1)示例文档

> db.scores.find()
{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
> db.scores.createIndex( { score: 1 } , { sparse: true } )

2)查询结果

#COLLSCAN,未使用索引
> db.scores.find().sort( { score: -1 } )
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }

#强制使用稀疏索引后,得到记录只有2条
> db.scores.find().sort( { score: -1 } ).hint( { score: 1 } )
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
>

4、稀疏索引 + 唯一索引对唯一性的限制

稀疏 + 唯一索引的文档,仅仅限制满足稀疏索引字段唯一,不包含稀疏索引字段的文档可重复

1)示例集合

db.scores.createIndex( { score: 1 } , { sparse: true, unique: true } )
> db.scores.find()
{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }

2)查询结果

> db.scores.insert( { "userid": "AAAAAAA", "score": 43 } )
WriteResult({ "nInserted" : 1 })
> db.scores.insert( { "userid": "BBBBBBB", "score": 34 } )
WriteResult({ "nInserted" : 1 })
> db.scores.insert( { "userid": "CCCCCCC" } )          //没有score稀疏索引字段,不要求满足唯一性
WriteResult({ "nInserted" : 1 })
> db.scores.insert( { "userid": "DDDDDDD" } )
WriteResult({ "nInserted" : 1 })
>
> db.scores.insert( { "userid": "AAAAAAA", "score": 82 } )     //score满足稀疏索引必须满足唯一性
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 11000,
        "errmsg" : "E11000 duplicate key error collection: test.scores index: score_1 dup key: { : 82.0 }"
    }
})
> db.scores.insert( { "userid": "BBBBBBB", "score": 90 } )
WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 11000,
        "errmsg" : "E11000 duplicate key error collection: test.scores index: score_1 dup key: { : 90.0 }"
    }
})
相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
3月前
|
存储 NoSQL 关系型数据库
|
6月前
|
NoSQL MongoDB 索引
【最佳实践】MongoDB导入数据时重建索引
【最佳实践】MongoDB导入数据时重建索引
168 0
|
7月前
|
JSON NoSQL MongoDB
mongodb基本操作,增删改查,查询,索引,权限机制
mongodb基本操作,增删改查,查询,索引,权限机制
|
6月前
|
NoSQL MongoDB 索引
开心档-软件开发入门之MongoDB 覆盖索引查询
开心档-软件开发入门之MongoDB 覆盖索引查询
45 0
|
15天前
|
NoSQL MongoDB 索引
【MongoDB】MongoDB 覆盖索引
【4月更文挑战第3天】【MongoDB】MongoDB 覆盖索引
|
3月前
|
存储 NoSQL 关系型数据库
4-MongoDB索引知识
MongoDB索引知识
|
3月前
|
NoSQL MongoDB 索引
【待完善】MongoDB - 使用索引
【待完善】MongoDB - 使用索引
30 0
|
3月前
|
存储 NoSQL MongoDB
MongoDB之索引和聚合
【1月更文挑战第21天】 一、索引 1、说明 2、原理 3、相关操作 3.1、创建索引 3.2、查看集合索引 3.3、查看集合索引大小 3.4、删除集合所有索引(不包含_id索引) 3.5、删除集合指定索引 4、复合索引 二、聚合 1、说明 2、使用
61 0
|
9月前
|
存储 NoSQL MongoDB
【mongo 系列】mongodb 学习七,索引实操练习
向 mydoc 集合中,插入多条数据,mydoc 之前是没有存在过的,我们直接使用 db.mydoc.insertMany() ,mongodb 会默认给我们新建这个集合
|
5月前
|
存储 NoSQL Cloud Native
mongodb 索引实操
mongodb 索引实操