MongoDB开发深入之二:索引
索引分类:
- 默认索引
- 单一索引
- 复合索引
- 多键索引(数组索引)
- 全文检索索引
- 2dsphere 索引
- 2D索引
- ......
索引属性:
- 到期TTL
- 唯一索引
- 部分索引
- 稀疏索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。特别在处理大量的数据时,查询甚至几分钟,这对网站的性能是非常致命的。
默认索引
默认情况下,所有集合都在_id 字段上有索引。
单一索引
一个名为records
的集合,它包含类似于以下 sample 文档的文档:
{ "_id": ObjectId("570c04a4ad233577f97dc459"), "score": 1034, "location": { state: "NY", city: "New York" } }
以下操作在records
集合的score
字段上创建升序索引:
db.records.createIndex( { score: 1 } )
创建的索引将支持在字段score
上选择的查询,如下所示:
db.records.find( { score: 2 } ) db.records.find( { score: { $gt: 10 } } )
一个名为records
的集合,以下文档:
{ "_id": ObjectId("570c04a4ad233577f97dc459"), "score": 1034, "location": { state: "NY", city: "New York" } }
以下操作在location.state
字段上创建索引:
db.records.createIndex( { "location.state": 1 } )
创建的索引将支持在字段location.state
上选择的查询,如下所示:
db.records.find( { "location.state": "CA" } ) db.records.find( { "location.city": "Albany", "location.state": "NY" } )
复合索引
一个名为products
的集合,它包含类似于以下文档的文档:
{ "_id": ObjectId(...), "item": "Banana", "category": ["food", "produce", "grocery"], "location": "4th Street Store", "stock": 4, "type": "cases" }
以下操作在item
和stock
字段上创建升序索引:
db.products.createIndex( { "item": 1, "stock": 1 } )
索引将包含首先按item
字段的值排序的文档的 references,并且在item
字段的每个 value 内,按 stock 字段的值排序。
一个包含username
和date
字段的文档的集合events
。 Applications 可以发出 return 结果首先按升序username
值排序,然后降序(i.e.更近期到最后)date
值的查询,例如:
db.events.find().sort( { username: 1, date: -1 } )
或者 return 结果首先按降序username
值排序,然后按升序date
值排序,例如:
db.events.find().sort( { username: -1, date: 1 } )
以下索引可以支持这两种排序操作:
db.events.createIndex( { "username" : 1, "date" : -1 } )
但是,上面的索引不能支持按升序username
值排序,然后升序date
值,如下所示:
db.events.find().sort( { username: 1, date: 1 } )
索引前缀
索引前缀是索引字段的起始子集。对于 example,请考虑以下复合索引:
{ "item": 1, "location": 1, "stock": 1 }
索引具有以下索引前缀:
-
{ item: 1 }
-
{ item: 1, location: 1 }
对于复合索引,MongoDB 可以使用索引来支持对索引前缀的查询。因此,MongoDB 可以在以下字段中使用索引进行查询:
-
item
字段, -
item
字段和location
字段, -
item
字段和location
字段以及stock
字段。
MongoDB 还可以使用索引来支持item
和stock
字段上的查询,因为item
字段对应于前缀。但是,索引在支持查询时效率不高,因为只有item
和stock
的索引。
但是,MongoDB 无法使用索引来支持包含以下字段的查询,因为没有item
字段,列出的字段中的任何一个都对应于前缀索引:
-
location
字段, -
stock
字段,或 -
location
和stock
字段。
多键索引(数组索引)
MongoDB 会为 array 中的每个元素创建索引 key。这些多键索引支持对 array 字段的有效查询。可以在包含标量值(e.g .strings,numbers)和嵌套文档的数组上构建多键索引。
inventory
集合:
{ _id: 5, type: "food", item: "aaa", ratings: [ 5, 8, 9 ] } { _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 ] }
该集合在ratings
字段上有一个多键索引:
db.inventory.createIndex( { ratings: 1 } )
以下查询查找ratings
字段为 array [ 5, 9 ]
的文档:
db.inventory.find( { ratings: [ 5, 9 ] } )
MongoDB 可以使用多键索引查找ratings
array 中任何位置5
的文档。然后,MongoDB 为ratings
array 等于查询 array [ 5, 9 ]
的文档检索这些文档。
全文检索索引
MongoDB 提供文本索引以支持对 string 内容的文本全文搜索查询。 text索引可以包含 value 是 string 或 string 元素的 array 的任何字段。
2dsphere 索引
2dsphere索引支持计算 earth-like 球体上的几何的查询。 2dsphere index 支持所有 MongoDB 地理空间查询:包含,交集和邻近的查询。
以下操作在位置字段loc
上创建索引:
db.places.createIndex( { loc : "2dsphere" } )
位置索引的查询:
- GeoJSON Objects 由多边形限定
- GeoJSON Objects 的交集
- 靠近 GeoJSON 点
- 球体上定义的圆内点
以下 example 选择完全存在于 GeoJSON 多边形内的所有点和形状:
db.places.find( { loc : { $geoWithin : { $geometry : { type : "Polygon" , coordinates : [ [ [ 0 , 0 ] , [ 3 , 6 ] , [ 6 , 1 ] , [ 0 , 0 ] ] ] } } } } )
到期TTL
TTL 索引是 MongoDB 可用于在一定量时间(秒)之后自动从集合中删除文档的特殊单一索引。
数据到期对于某些类型的信息非常有用,例如机器生成的 event 数据,日志和 session 信息,这些信息只需要在数据库中持续有限的 time 时间。
要创建 TTL 索引,请在 value 为日期的字段或包含date 值的 array 的字段上使用db.collection.createIndex()方法和expireAfterSeconds选项。
例如,要在eventlog集合的lastModifiedDate字段上创建 TTL 索引,请在mongo shell 中使用以下操作:
db.eventlog.createIndex( { "lastModifiedDate": 1 }, { expireAfterSeconds: 3600 } )
限制
- TTL 索引是 single-field 索引。 复合指数不支持 TTL 并忽略expireAfterSeconds选项。
- _id字段不支持 TTL 索引。
- 您无法在上限集合上创建 TTL 索引,因为 MongoDB 无法从上限集合中删除文档。
- 您不能使用createIndex()更改现有索引的expireAfterSeconds的 value。而是将collMod database 命令与指数 collection flag 结合使用。否则,要更改现有索引选项的 value,必须先删除索引并重新创建。
- 如果字段已存在 non-TTL single-field 索引,则无法在同一字段上创建 TTL 索引,因为您无法创建具有相同 key 规范且仅由选项不同的索引。要将 non-TTL single-field 索引更改为 TTL 索引,必须先删除索引并使用expireAfterSeconds选项重新创建。
唯一索引
唯一索引可确保索引字段不存储重复值;
在members
集合的user_id
字段上创建唯一索引:
db.members.createIndex( { "user_id": 1 }, { unique: true } )
部分索引
部分索引仅索引符合指定过滤器表达式的集合中的文档。通过索引集合中文档的子集,部分索引具有较低的存储要求,并降低了索引创建和维护的性能成本。
创建partial索引,请将db.collection.createIndex()方法与partialFilterExpression选项一起使用。 partialFilterExpression选项接受使用以下内容指定过滤条件的文档:
- 等式表达式(value或使用$eq operator),
- $exists:true表达,
- $gt,$gte,$lt,$lte表达式,
- $type表达式,
- 只有 top-level 的$and operator
该索引仅索引rating
字段大于 5 的文档。
db.restaurants.createIndex( { cuisine: 1, name: 1 }, { partialFilterExpression: { rating: { $gt: 5 } } } )
稀疏索引
稀疏索引仅包含具有索引字段的文档的条目,即使索引字段包含 null value 也是如此。索引会跳过缺少索引字段的任何文档。索引是“稀疏的”,因为它不包含集合的所有文档。相比之下,non-sparse 索引包含集合中的所有文档,为那些不包含索引字段的文档存储空值。
默认情况下稀疏的索引:
2 dsphere(version 2),2 d,geoHaystack和文本索引始终为稀疏索引。
以下操作会在addresses
集合的xmpp_id
字段上创建稀疏索引:
db.addresses.createIndex( { "xmpp_id": 1 }, { sparse: true } )
目前维护的开源产品:https://gitee.com/475660