- MongoDB的索引用于查询(find、findOne)和排序。
- 如果倾向于在集合中大量使用排序,那么应该根据排序的需求添加索引。如果在一个没有索引的集合中对目标字段使用sort(),并且数据量超过内部排序缓冲的最大大小,就会看到错误消息。
- 在集合中添加索引后,MongoDB必须维护它们,并在每次执行写操作(例如更新、插入,或删除)时对它们进行更新。如果在集合中有过多的索引,它们有可能会对写操作的性能造成负面影响。
- 索引最好用在读操作多的集合中。写入频繁的集合(例如日志系统),引入索引可能会减少每秒写入的文档数量峰值(这些文档可能会大量涌入集合中)。
- 每个集合中最多有64个索引。
1、查看索引
- getIndexes函数会显示指定集合中的索引。显示所有索引,包括它们引用的字段或元素,以及在索引上设置的任何选项。
- getIndexes函数的基本语法格式如下:
db.collection.getIndexes()
- 当在某个元素上定义索引时,MongoDB将构造一个二叉树索引,并用它高效地定位文档。如果未找到合适的索引,MongoDB将扫描集合中的所有文档,搜索满足查询的记录。
示例:
- people集合没有任何用户自定义的索引,但MongoDB自动为这个集合的_id字段创建了索引。不需要做任何操作来创建或删除_id_索引,MongoDB将在集合创建时创建该索引,在集合删除时删除该索引。
> db.people.getIndexes() [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" } ]
2、创建索引
- createIndex函数的基本语法格式如下:
- 首先将检查目前集合中是否已经创建了该索引。如果是,那么createlndex()只是返回该索引。
//在集合上创建索引 db.collection.createIndex(keys, options, commitQuorum) //在集合上创建一个或多个索引 db.collection.createIndexes( [ keyPatterns ], options, commitQuorum )
- createIndex函数的参数:
- keys:包含字段和值的文档,其中字段是索引键,值是该字段的索引类型。对于字段的升序索引值是1; 对于降序索引,值是-1。从3.6开始,不能指定*为索引名称。
- options:可选的。包含一组控制创建索引的选项的文档
- commitQuorum:可选的。提交法定人数
- options可用参数有:
//可用于所有索引类型的option background: boolean,可选的。在MongoDB 4.2中已弃用。"background: true"指示MongoDB在后台构建索引。默认值为false。 unique: boolean,可选的。是否创建唯一索引。若为true,则创建唯一索引。默认值为false。 name: string,可选的。索引的名称。如果未指定,MongoDB通过连接索引字段的名称和排序顺序来生成索引名。 partialFilterExpression: document,可选的。如果指定,索引只引用匹配筛选器表达式的文档。 sparse: boolean,可选的。如果为true,则索引只引用具有指定字段的文档。默认值为false。 expireAfterSeconds: integer,可选的。指定一个值(以秒为单位)作为TTL,以控制MongoDB在这个集合中保留文档的时间。 hidden: boolean,可选的。用于确定是否对查询计划器隐藏索引。 storageEngine: document,可选的。在创建索引时指定存储引擎。 //可用于排序的option collation: { //可选的。指定索引的排序规则。 locale: <string>, caseLevel: <boolean>, caseFirst: <string>, strength: <int>, numericOrdering: <boolean>, alternate: <string>, maxVariable: <string>, backwards: <boolean> } //文本(text)索引选项 weights: document,可选的。对于文本索引,是包含字段和权重对的文档。权重是1到99,999之间的整数,表示该字段相对于其他索引字段的重要性。可以为部分或所有索引字段指定权重。参见使用权重控制搜索结果来调整分数。缺省值为1。 default_language: string,可选的。对于文本索引,确定停止词列表以及词干分析器和标记分析器的规则的语言。 language_override: string,可选的。对于文本索引,是集合文档中包含文档的覆盖语言的字段的名称。默认值为language。 textIndexVersion: integer,可选的。文本索引版本号。用户可以使用此选项覆盖默认版本号。
2.1、创建简单索引
- 使用嵌入式文档中的字段,可使用普通的点标记寻址模式。
- 如果指定的文档字段是数组类型,那么该索引将把数组中的所有元素作为不同的索引条目添加到其中。这称为多键索引,每个文档都将被链接到索引中的多个值。使用检查explain()就会看到其中提到了多值索引。
示例:
- 创建升序或降序索引。
//插入数据 db.media.insert({"Type":"CD", "Artist":"Nirvana", "Title":"Nevermind", "Genre":"Grunge", "Releasedate":"1991.09.24", "Tracklist":[{"Track":"1", "Title":"You Know You're Right", "Length":"3:38"}, {"Track":"5", "Title":"Smells Like Teen Spirit", "Length":"5:02"}]}) db.media.insert({"Type":"Book", "Title":"Definitive Guideto MongoDB 3rd ed.", "ISBN":"978-1-4842-1183-0", "Publisher":"Apress", "Author":["Hows, David", "Plugge, Eelco", "Membrey, Peter", "Hawkins, Tim"]}) //在Type字段上创建一个简单的升序二叉树索引 > db.media.createIndex({"Type": 1}) //在Tracklist.Title字段上创建一个简单的降序二叉树索引 > db.media.createIndex({"Tracklist.Title": 1}) //查看索引 > > db.media.getIndexes() [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" }, { "v" : 2, "key" : { "Type" : 1 }, "name" : "Type_1" }, { "v" : 2, "key" : { "Tracklist.Title" : 1 }, "name" : "Tracklist.Title_1" } ]
2.2、创建复合索引
- 为查询中所有用到的字段都分别创建索引(即为每个字段都创建一个索引)。这种方式可能会加快查询的速度,但会降低添加和删除数据的速度,因为在每次执行修改操作时都要更新这些索引。
- 查询过程只会使用一个索引,所以添加许多小索引通常并不会改善查询性能。
- 复合索引提供了一种减少集合中索引数目的方法,它允许将多个字段结合在一起创建个索引,所以应该尽量使用复合索引。
- 复合索引有两种:子文档索引和手动定义的复合索引。
- 可以在查询时不使用所有复合索引键的情况下使用复合索引。因此,可以构造出一组复合索引,覆盖到所有希望在集合中执行的查询,而不需要单独索引每个字段(从而避免对插入/更新操作的性能造成负面影响)。
- 复合索引在使用索引进行排序时就没那么有用了。排序并不善于利用复合索引,除非数据项的列表和排序与索引结构匹配。
1、创建简单复合索引
- 使用子文档中的字段作为索引键时,构建多键索引的字段顺序,要与它们在子文档中的顺序相同。许多情况下,这种方式都无法对创建索引的过程进行充分控制。
- 为解决这个限制,并保证查询使用以目标方式构建的索引,需要查询的文档结构与创建索引所使用的子文档结构相同。
- 还可为所有用于创建复合索引的字段显式命名,然后指定这些字段的结合顺序。
示例1:
//插入数据 db.media.insert({"Type":"Book", "Title":"Definitive Guideto MongoDB 3rd ed.", "ISBN":"978-1-4842-1183-0", "Publisher":"Apress", "Author":["Hows, David", "Plugge, Eelco", "Membrey, Peter", "Hawkins, Tim"]}) db.media.insert({"Type":"CD", "Artist":"Nirvana", "Title":"Nevermind", "Genre":"Grunge", "Releasedate":"1991.09.24", "Tracklist":[{"Track":"1", "Title":"You Know You're Right", "Length":"3:38"}, {"Track":"5", "Title":"Smells Like Teen Spirit", "Length":"5:02"}]}) //创建复合索引 > db.media.createIndex({"Tracklist.Track": 1, "Tracklist.Length": 1}) //使用符合索引 > db.media.find({"Tracklist.Track": "1", "Tracklist.Length":"3:38"}).explain('executionStats')
示例2:
//在orderDate字段(按升序)和zipcode字段(按降序)上创建复合索引。 db.collection.createIndex( { orderDate: 1, zipcode: -1 } ) //state字段(按升序)和zipcode字段(散列)上创建复合索引(从MongoDB 4.4开始,复合索引可以包含单个散列) db.collection.createIndex( { "state" : 1, "zipcode" : "hashed" } )
2、MongoDB选择索引的方式
- 优化器在为查询选择“最佳索引”时考虑的因素?
- 最优索引必须包括查询的所有过滤字段和排序字段。
- 查询中任何范围过滤字段或排序字段必须在相等字段的后面(如果当前查询条件有多个最优索引,则MongoDB使用先前成功的计划,除非其执行性能不如另一个计划)。
示例:
//插入数据 db.student.insert({"id":1, "name": "hh1", "age": 22, "class": 3}) db.student.insert({"id":2, "name": "hh2", "age": 22, "class": 5}) db.student.insert({"id":3, "name": "hh3", "age": 23, "class": 1}) db.student.insert({"id":4, "name": "hh4", "age": 22, "class": 2}) //创建索引前执行查找 > db.student.find({id: {$gte: 2, $lte: 4}}).explain('executionStats') "executionStats" : { "executionSuccess" : true, "nReturned" : 3, #符合查询条件的文档数 "executionTimeMillis" : 0, #查询计划选择和查询执行所需的总时间(以毫秒为单位) "totalKeysExamined" : 0, #扫描的索引条目数 "totalDocsExamined" : 4, #在查询执行期间检查的文档数 ... //创建简单索引 > db.student.createIndex({"id": 1}) //执行查找 > db.student.find({id: {$gte: 2, $lte: 4}}).explain('executionStats') "executionStats" : { "executionSuccess" : true, "nReturned" : 3, "executionTimeMillis" : 0, "totalKeysExamined" : 3, "totalDocsExamined" : 3, ... //执行查找,范围和相等查询 > db.student.find({id: {$gte: 2, $lte: 4}, age: 22}).explain('executionStats') "executionStats" : { "executionSuccess" : true, "nReturned" : 2, "executionTimeMillis" : 0, "totalKeysExamined" : 3, "totalDocsExamined" : 3, ... //创建符合索引 > db.student.createIndex({"id": 1, "age": 1}) //执行查找 > db.student.find({id: {$gte: 2, $lte: 4}, age: 22}).explain('executionStats') "executionStats" : { "executionSuccess" : true, "nReturned" : 2, "executionTimeMillis" : 1, "totalKeysExamined" : 3, "totalDocsExamined" : 3, ... //创建索引 > db.student.createIndex({"age": 1, "id": 1}) //执行查找 > db.student.find({id: {$gte: 2, $lte: 4}, age: 22}).explain('executionStats') "executionStats" : { "executionSuccess" : true, "nReturned" : 2, "executionTimeMillis" : 1, "totalKeysExamined" : 2, "totalDocsExamined" : 2, ...
3、创建复杂复合索引
- 创建复合索引时,索引字段的顺序:
- (1)相等测试:按任意顺序把所有相等测试的字段添加到复合索引中。
- (2)排序字段:在索引中添加排序字段,其顺序、方向和查询的排序相同。(只有存在多个排序字段,升序/降序才重要)
- (3)范围过滤器:首先,为基数最低的字段添加范围过滤器(集合中不同的值最少),接着添加基数最低的范围过滤器,直到基数最高的范围过滤器为止。
- 如果相等测试字段或范围过滤器字段没有过滤掉90%的文档,就可以省略它们,以减少索引的大小。
- 如果集合上有几个索引,就可能需要提示Mongo使用正确的索引。
2.3、在后台创建索引
db.collection.createIndex(keys, {background: true})
- 使用createlndex()函数创建索引时,服务器必须读取集合中的所有数据并创建指定的索引。
- 默认情况下,索引构建将在前台完成,集合所在数据库上的所有操作都将被阻塞,直至索引操作完成。
- MongoDB因此引入了一个特性,它允许索引构建在后台执行。在后台构建索引的过程中,其他连接在数据库上的操作(读和写)并不会被阻塞。一旦索引创建完成,所有需要使用索引的查询都将立即使用它。值得注意的是,索引在后台构建时将耗费更长的时间。
- 如果创建索引的操作已经挂起或者花费了太长时间,那么可以终止该操作。终止该操作后,已完成的部分索引也将被删除,防止数据库中出现损坏或无关的数据。
//查看目前MongoDB实例中运行的所有操作的列表(获取操作ID) db.currentOp() //通过操作ID终止操作 db.killOp(opid)
示例:
> db.student.createIndex({"age": 1, "name": 1}, {background: true})
2.4、创建唯一索引
1
# #标签:创建,db,索引,字段,文档,id,MongoDB09 From: https://www.cnblogs.com/maiblogs/p/16709685.html