MongoDB 索引之介绍与使用
2015-03-19 21:07
531 查看
MongoDB中的索引其实类似于关系型数据库,都是为了提高查询和排序的效率的,并且实现原理也基本一致,大部分优化MySQL索引的技巧也同样适用于mongodb。由于集合中的键(字段)可以是普通数据类型,也可以是子文档。MongoDB可以在各种类型的键上创建索引。索引是对数据库表中一列或多列的值进行排序的一种特殊的数据结构,存储在一个易于遍历读取的数据集合中。当查询中用到某些条件时,可以对该键建立索引,能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。然而,这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,性能非常低下,没法接受的。
索引有方向的,倒序还是升序。每个集合默认的最大索引个数为64个。
下面分别讲解各种类型的索引的创建,查询,以及索引的维护等。
初始化数据:
一、创建索引
语法:
>db.COLLECTION_NAME.ensureIndex({KEY:1})
KEY 值为要创建的索引字段,1为指定按升序创建索引,如果你想按降序来创建索引指定为-1即可。
ensureIndex() 也可以设置使用多个字段创建索引(在关系型数据库中称作复合索引)。
实例:
可接受的参数:
二、查看索引
语法:
> db.COLLECTION_NAME.getIndexes() 或者db.system.indexes.find()
查看实例:
查询索引大小:
语法:
> db.COLLECTION_NAME.totalIndexSize()
三、删除索引
关系型数据库中,表被删除了,索引也不会存在。在MongoDB中不存在删除集合的说法,就算集合数据清空,索引都是还在的,要移除索引还需要手工删除。
语法:
db.COLLECTION_NAME.dropIndex(index)
db.COLLECTION_NAME.dropIndexes() //删除全部索引,_id索引不会被删除
四、重建索引
重建索引会锁住集合的。用repair命令修复数据库时,会重建索引的。
语法:
>db.collection.reIndex()或db.runCommand({reIndex:'collection'})
五、索引分类
1.默认索引
MongoDB有个默认的"_id"的键,他相当于"主键"的角色。集合创建后系统会自动创建一个索引在"_id"键上,它是默认索引,索引名叫"_id_",是无法被删除的。
2.单列索引
在单个键上创建的索引就是单列索引,如我们创建的db.user.ensureIndex({"name" : 1}
3.组合索引
同时对多个键创建组合索引。如下:
对多个值进行组合索引,查询时,子查询与索引前缀匹配时,才可以使用该组合索引。
4.嵌入式索引
为内嵌文档的键创建索引与普通的键创建索引并无差异。
如:
5.文档式索引
索引建立在嵌入式文档类型的字段上。
如:
6.唯一索引
只需要在ensureIndex命名中指定"unique:true"即可。唯一索引限制了对当前键添加值时,不能添加重复的信息。值得注意的是,当文档不存在指定键时,会被认为键值是“null”,所以“null”也会被认为是重复的,所以一般被作为唯一索引的键,最好都要有键值。可以使用dropDups来保留第一个文档,而后的重复文档将删除,这种方法慎重操作。
7.sparse索引
对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档。默认值为 false。解决索引文件过大的问题。不会对该键值为空的行做索引。
>db.user.ensureIndex({name:1},{sparse:true});
8.过期索引-expireAfter
指定一个值,以秒为TTL控制多久MongoDB的文档保留在此集合。储存在过期时间的字段必须是时间类型(ISODate或ISODate数组),不能使用复合索引。如果使用的是ISODate数组,则按照最小时间进行删除。
>db.user.ensureIndex({name:1},{expireafterseconds:3600});
9.covered索引
如果你查找的值正好是在索引中,则可以直接返回索引中存的值,而不用到数据文件中查找。当用explain时,当indexOnly=true,表示有用到covered index。
10.全文索引
mongodb全文索引是在2.4版本引入的,下一节介绍。
11.理位置索引
关于LBS相关项目,一般存储每个地点的经纬度的坐标, 如果要查询附近的场所,则需要建立索引来提升查询效率。 Mongodb专门针对这种查询建立了地理空间索引。 2d和2dsphere索引,分别是针对平面和球面。
五、强制使用索引
如果发现用了非预期的索引,可以用hint来强制使用某个索引。使用hint命令,并不是所有操作走索引一定快。
如:> db.user.find({age:{$lt:20}}).hint({name:1,age:1})
使用explain命令查看执行计划,看看有没有走索引。
如上没有走索引。加上hint强制使用索引,如下:
如上使用了索引耗时(millis)反而变大。大多数情况下没必要指定,mongodb会选择用哪个索引,初次查询时,查询优化器会同时尝试各种查询方案,最先完成的被确定使用,其他的则终止掉。查询方案也会记录下来,查询优化器也会定期重试其他的方案,以防新的数据增加或索引改变,之前的方案不再是最优的。
索引有方向的,倒序还是升序。每个集合默认的最大索引个数为64个。
下面分别讲解各种类型的索引的创建,查询,以及索引的维护等。
初始化数据:
db.user.save({"name":"Jack","age":25}); db.user.save({"name":"Jack","age":10}); db.user.save({"name":"Lucy","age":22}); db.user.save({"name":"Lucy","age":33}); db.user.save({"name":"Lilei","age":30}); for(var i=0;i<10000;i++){db.user.save({"name":"Jack"+i,"age":(i+10)%100});}
一、创建索引
语法:
>db.COLLECTION_NAME.ensureIndex({KEY:1})
KEY 值为要创建的索引字段,1为指定按升序创建索引,如果你想按降序来创建索引指定为-1即可。
ensureIndex() 也可以设置使用多个字段创建索引(在关系型数据库中称作复合索引)。
实例:
>db.user.ensureIndex({"name" : 1},{'background':true});
可接受的参数:
Parameter | Type | Description |
---|---|---|
background | Boolean | 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 “background” 可选参数。 “background” 默认值为false。 |
unique | Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. |
name | string | 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 |
dropDups | Boolean | 在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false. |
sparse | Boolean | 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false. |
expireAfterSeconds | integer | 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。 |
v | index version | 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。 |
weights | document | 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。 |
default_language | string | 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语 |
language_override | string | 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language. |
语法:
> db.COLLECTION_NAME.getIndexes() 或者db.system.indexes.find()
查看实例:
> db.user.getIndexes(); [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "lmis.user", "name" : "_id_" }, { "v" : 1, "key" : { "name" : 1 }, "ns" : "lmis.user", "name" : "name_1", "background" : true } ]
查询索引大小:
语法:
> db.COLLECTION_NAME.totalIndexSize()
> db.user.totalIndexSize(); 842128
三、删除索引
关系型数据库中,表被删除了,索引也不会存在。在MongoDB中不存在删除集合的说法,就算集合数据清空,索引都是还在的,要移除索引还需要手工删除。
语法:
db.COLLECTION_NAME.dropIndex(index)
db.COLLECTION_NAME.dropIndexes() //删除全部索引,_id索引不会被删除
>db.user.dropIndexes(); { "nIndexesWas" : 2, "msg" : "non-_id indexes dropped for collection", "ok" : 1 }
四、重建索引
重建索引会锁住集合的。用repair命令修复数据库时,会重建索引的。
语法:
>db.collection.reIndex()或db.runCommand({reIndex:'collection'})
>db.user.reIndex() { "nIndexesWas" : 1, "msg" : "indexes dropped for collection", "nIndexes" : 1, "indexes" : [ { "key" : { "_id" : 1 }, "ns" : "lmis.user", "name" : "_id_" } ], "ok" : 1 }
五、索引分类
1.默认索引
MongoDB有个默认的"_id"的键,他相当于"主键"的角色。集合创建后系统会自动创建一个索引在"_id"键上,它是默认索引,索引名叫"_id_",是无法被删除的。
2.单列索引
在单个键上创建的索引就是单列索引,如我们创建的db.user.ensureIndex({"name" : 1}
3.组合索引
同时对多个键创建组合索引。如下:
>db.user.ensureIndex({"name" : 1,"age" : 1} //以下的查询将使用到此索引 > db.user.find({"name":'Jack',"age":20}) > db.user.find({"name":'Jack'}) > db.user.find().sort({"name":1})
对多个值进行组合索引,查询时,子查询与索引前缀匹配时,才可以使用该组合索引。
4.嵌入式索引
为内嵌文档的键创建索引与普通的键创建索引并无差异。
如:
> db.user.save({"name":"Jack","age":25,"address":{"city":"beijing"}}); > db.user.ensureIndex({"address.city":1})
5.文档式索引
索引建立在嵌入式文档类型的字段上。
如:
> db.user.save({"name":"Jack","age":25,"address":{"city":"beijing"}}); > db.user.ensureIndex({"address":1})
6.唯一索引
只需要在ensureIndex命名中指定"unique:true"即可。唯一索引限制了对当前键添加值时,不能添加重复的信息。值得注意的是,当文档不存在指定键时,会被认为键值是“null”,所以“null”也会被认为是重复的,所以一般被作为唯一索引的键,最好都要有键值。可以使用dropDups来保留第一个文档,而后的重复文档将删除,这种方法慎重操作。
>db.user.ensureIndex({name:1},{unique:true});
7.sparse索引
对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档。默认值为 false。解决索引文件过大的问题。不会对该键值为空的行做索引。
>db.user.ensureIndex({name:1},{sparse:true});
8.过期索引-expireAfter
指定一个值,以秒为TTL控制多久MongoDB的文档保留在此集合。储存在过期时间的字段必须是时间类型(ISODate或ISODate数组),不能使用复合索引。如果使用的是ISODate数组,则按照最小时间进行删除。
>db.user.ensureIndex({name:1},{expireafterseconds:3600});
9.covered索引
如果你查找的值正好是在索引中,则可以直接返回索引中存的值,而不用到数据文件中查找。当用explain时,当indexOnly=true,表示有用到covered index。
10.全文索引
mongodb全文索引是在2.4版本引入的,下一节介绍。
11.理位置索引
关于LBS相关项目,一般存储每个地点的经纬度的坐标, 如果要查询附近的场所,则需要建立索引来提升查询效率。 Mongodb专门针对这种查询建立了地理空间索引。 2d和2dsphere索引,分别是针对平面和球面。
五、强制使用索引
如果发现用了非预期的索引,可以用hint来强制使用某个索引。使用hint命令,并不是所有操作走索引一定快。
如:> db.user.find({age:{$lt:20}}).hint({name:1,age:1})
使用explain命令查看执行计划,看看有没有走索引。
> db.user.find({age:{$lt:30}}).explain() { "cursor" : "BasicCursor", "isMultiKey" : false, "n" : 3004, "nscannedObjects" : 10006, "nscanned" : 10006, "nscannedObjectsAllPlans" : 10006, "nscannedAllPlans" : 10006, "scanAndOrder" : false, "indexOnly" : false, "nYields" : 0, "nChunkSkips" : 0, "millis" : 9, "indexBounds" : { //没有走索引 }, "server" : "100.205:27017" }
如上没有走索引。加上hint强制使用索引,如下:
> db.user.find({age:{$lt:30}}).hint({name:1,age:1}).explain() { "cursor" : "BtreeCursor name_1_age_1", "isMultiKey" : false, "n" : 3004, "nscannedObjects" : 3004, "nscanned" : 9817, "nscannedObjectsAllPlans" : 3004, "nscannedAllPlans" : 9817, "scanAndOrder" : false, "indexOnly" : false, "nYields" : 0, "nChunkSkips" : 0, "millis" : 34, "indexBounds" : { "name" : [ [ { "$minElement" : 1 }, { "$maxElement" : 1 } ] ], "age" : [ [ -1.7976931348623157e+308, 30 ] ] }, "server" : "100.205:27017" }
如上使用了索引耗时(millis)反而变大。大多数情况下没必要指定,mongodb会选择用哪个索引,初次查询时,查询优化器会同时尝试各种查询方案,最先完成的被确定使用,其他的则终止掉。查询方案也会记录下来,查询优化器也会定期重试其他的方案,以防新的数据增加或索引改变,之前的方案不再是最优的。
相关文章推荐
- 数据库索引介绍及使用
- 数据库索引介绍及使用
- Msql索引的介绍 优点和缺点和使用过程中要注意的一些事项 挺好的
- 基于B-树和B+树的使用:数据搜索和数据库索引的详细介绍
- 基于B-树和B+树的使用:数据搜索和数据库索引的详细介绍
- 部分行索引使用介绍
- MongoDB索引的使用
- MongoDB中索引的创建和使用详解
- mongodb 索引问题的介绍
- 部分行索引使用介绍
- MongoDB随笔3:使用索引
- Mysql索引介绍与使用
- 使用NOSQL的MongoDB建立索引时需要注意的几点建议和Explain优化分析
- MongoDB中索引的创建和使用详解
- 学习MongoDB--(5-2):索引(查看索引的使用,管理索引)
- 空间索引使用的意义及网格索引和四叉树索引简单介绍
- MagicMongoDBTool数据管理工具使用介绍
- PostgreSQL 8.3 以上的中文全文索引使用介绍
- SQLSERVER如何查看索引缺失及DMV使用介绍
- mongoDB 索引使用