MongoDB索引
前言
在MongoDB中,索引通常能够极大的提高查询的效率。如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文档并选取那些符合查询条件的记录。如果有一个合适的索引来进行查询,则可以限制扫描文档的数量。
索引是特殊的数据结构,存储在一个易于遍历读取的数据集合中,它是对数据库表中一列或多列的值进行排序的一种结构。索引条目的排序支持高效的匹配和基于范围的查询操作,同时,MongoDB可以通过使用索引返回排序后的结果。
下面的示意图表明如何通过索引筛选和整理匹配的文档。($lt
条件操作符表示小于,{score:-1或者1}
表示逆向排序或者正向排序)
从本质上来说,MongoDB中的索引与其他数据库系统中的索引相类似,对于集合中的任何域或者子域都支持索引。
默认索引 _id
MongoDB在创建集合时,会在_id
域创建一个唯一性的索引,即禁止插入两个具有相同_id
值的文档,同时该索引无法被删除。
查询、创建、删除索引
//查询索引
db.集合名.getIndexes()
//创建索引
db. 集合名.createIndex( <key and index type specification>, <options> )
//删除索引
db.集合名.dropIndex(<key and index type specification>)
常见索引
- 单键索引
MongoDB支持用户对文档的一个域创建单键索引,进行操作时,排列顺序并不重要因为无论升序还是降序,MongoDB均能做遍历。
假设有名为records
的集合,其中有一个记录如下:
{
"_id": ObjectId("570c04a4ad233577f97dc459"),
"userid": 1,
"score": 1034,
"location": { state: "NY", city: "New York" }
}
创建单键索引举例:
//这里的1不是值,而是代表排序方向,即升序
db.records.createIndex( { score: 1 } )
index-ascending
- 复合索引
当查询条件不止一个时,即要查询的字段不止一个时,就需要创建复合索引,最大字段数为31。
创建复合索引举例(排列原则为,先对userid进行排序,在userid相同的基础上,再对score进行排序):
db.collection.createIndex( {userid:1, score:-1} )
// 查询时,支持对多个字段查询,也支持对单个字段查询
db.collection.find( { userid: "aa1" } )
db.collection.find( { userid: "ca2", score: { $gt: 60} } )
index-compound-key
1)排序顺序:
假设一个集合
events
的文档有两个字段username
与date
,使用下面两条不同的语句查询:
db.events.find().sort( { username: 1, date: -1 } )
db.events.find().sort( { username: -1, date: 1 } )
可支持上面两条查询语句的索引为:
db.events.createIndex( { "username" : 1, "date" : -1 } )
但是,该索引却不支持下面的查询:
db.events.find().sort( { username: 1, date: 1 } )
更多详情可参考 Use Indexes to Sort Query Results(需翻墙)
2)前缀:
索引前缀是复合索引字段的子集。例如,考虑下面的复合:
{ "item": 1, "location": 1, "stock": 1 }
它的索引前缀为:
{ item: 1 }
{ item: 1, location: 1 }
该复合索引可查询的方法有如下几种:
the item field,
the item field and the location field,
the item field and the location field and the stock field.
当然还有the item field and the stock field
,因为item field
是一个索引前缀,当然这样的效率不及直接用item field and the stock field
作为一个复合索引。
但是,下面的查询方法是不支持的,因为缺少了item
字段而不符合索引前缀。
the location field,
the stock field,
the location and stock fields.
如果建立了复合索引,同时有一个单键索引与它的复合索引重复,当它们没有稀疏或者唯一的属性时,可把单键索引删去。因为MongoDB会在能使用复合索引前缀的任何情况下优先用之。
- 多键索引
多键索引和单键索引创建形式相同,区别在于字段的值。对于单键索引,字段的值为一个单一的值,如字符串,数字,日期。对于多键索引,值具有多个记录,如数组。为了给一个数组字段创建索引,MongoDB为数组中的每一个元素均创建一个索引键。多键索引支持高效查询数组字段,它可以被构建在包含字符串、数字类型或者嵌套文档的数组。
创建多键索引举例:
db.collection.createIndex( { addr.zip: 1 } )
index-multikey
1)限制
多键索引不支持以下几种情况:分片键、哈希索引、覆盖查询。
对于复合多键索引,多个字段不能同时为数组,但允许其中一个字段为数组。
MongoDB无法直接使用整个数组作为查询条件,而是将数组的第一个元素作为查询条件,得到符合第一个元素的文档,返回给MongoDB,再使用第二个元素作为查询条件,直到得到最终结果。
- 过期索引
顾名思义,即在一段时间后便会过期的索引,在索引过期后,相应的数据会被删除。适合存储在一段时间之后会失效的数据比如用户的登录信息、存储的日志。
创建过期索引举例(expireAfterSeconds
后的值表示多少秒后删除):
db.eventlog.createIndex( { "lastModifiedDate": 1 }, { expireAfterSeconds: 3600 } )
参考英文文档,由于英文水平不足,有些部分翻译会比较生硬。
如有建议,欢迎指出。