目录
1 索引
1.1 定义
索引
通常能够极大的提高查询的效率,如果没有索引,MongoDB
在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。
这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中
,索引是对数据库表中一列或多列的值进行排序的一种结构
由于索引存在于RAM
中,所以覆盖索引 从索引中获取数据比通过扫描文档读取数据要快得多
MongoDB
中索引大部分是排序的,排序索引意义:
- 在
MongoDB
中,排序操作,可以通过从索引中按照索引的顺序获取文档的方式,来保证结果的有序性。 - 如果
MongoDB
的查询计划器(planner)没法从索引中得到排序顺序,那么它就需要在内存中对结果排序,相比于不用索引的排序
操作,用索引会有更好的性能。 - 关键不用索引的排序操作,会在用了超过32MB内存时终止,也就是说MongoDB只能支持32MB的非索引排序
1.2 创建索引
MongoDB
使用 createIndex()
方法来创建索引
注意
:在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex()
,之后的版本使用了 db.collection.createIndex()
方法,ensureIndex()
还能用,但只是 createIndex()
的别名。
createIndex()
方法基本语法格式如下所示:
db.collection.createIndex(keys, options)
语法中 Key 值为要创建的索引字段,1
为指定按升序创建索引,如果想按降序来创建索引指定为 -1
即可
createIndex()
接收可选参数,可选参数列表如下:
Parameter | Type | Description |
---|---|---|
background | Boolean | 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false。 |
unique | Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. |
name | string | 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 |
dropDups | Boolean | 3.0+版本已废弃。在建立唯一索引时是否删除重复记录,指定 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.col.createIndex({"title":1})
createIndex() 方法中也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)
>db.col.createIndex({"title":1,"description":-1})
在后台创建索引
db.values.createIndex({open: 1, close: 1}, {background: true})
通过在创建索引时加 background:true 的选项,让创建工作在后台执行
1.3 查看删除索引
查看集合索引
db.col.getIndexes()
查看集合索引大小
db.col.totalIndexSize()
删除集合所有索引
db.col.dropIndexes()
删除集合指定索引
db.col.dropIndex("索引名称")
1.4 查询分析
MongoDB
查询分析可以确保我们所建立的索引是否有效,是查询语句性能分析的重要工具。
MongoDB
查询分析常用函数有:explain()
和 hint()
创建索引
db.test.createIndex({'title':1});
查询分析
db.test.find({'title':1}).explain();
分析结果:
// 1
{
"explainVersion": "1",
"queryPlanner": {
"namespace": "mydb.test",
"indexFilterSet": false,
"parsedQuery": {
"title": {
"$eq": 1
}
},
"queryHash": "6E0D6672",
"planCacheKey": "1953B8BB",
"maxIndexedOrSolutionsReached": false,
"maxIndexedAndSolutionsReached": false,
"maxScansToExplodeReached": false,
"winningPlan": {
"stage": "FETCH",
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"title": 1
},
"indexName": "title_1",
"isMultiKey": false,
"multiKeyPaths": {
"title": [ ]
},
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": NumberInt("2"),
"direction": "forward",
"indexBounds": {
"title": [
"[1.0, 1.0]"
]
}
}
},
"rejectedPlans": [ ]
},
"command": {
"find": "test",
"filter": {
"title": 1
},
"$db": "mydb"
},
"ok": 1
}
1.4.1 索引分析 explain
explain
操作提供了查询信息,使用索引及查询统计等。有利于我们对索引的优化。
接下来我们在 users
集合中创建 gender
和 user_name
的索引:
>db.users.createIndex({gender:1,user_name:1})
现在在查询语句中使用 explain :
>db.users.find({gender:"M"},{user_name:1,_id:0}).explain()
1.4.2 强制使用索引 hint
虽然MongoDB
查询优化器一般工作的很不错,但是也可以使用 hint
来强制 MongoDB
使用一个指定的索引。
这种方法某些情形下会提升性能。 一个有索引的 collection
并且执行一个多字段的查询
如下查询实例指定了使用 gender 和 user_name 索引字段来查询:
>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})
可以使用 explain()
函数来分析以上查询:
>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}).explain()
1.5 嵌套索引
示例文档如下:
{
"address": {
"city": "Los Angeles",
"state": "California",
"pin": "123"
},
"tags": [
"music",
"cricket",
"blogs"
],
"name": "Tom Benzamin"
}
1.5.1 索引数组字段
假设我们基于标签来检索用户,为此我们需要对集合中的数组 tags
建立索引。
在数组中创建索引,需要对数组中的每个字段依次建立索引。所以在我们为数组 tags 创建索引时,会为 music、cricket、blogs三个值建立单独的索引。
使用以下命令创建数组索引:
>db.users.createIndex({"tags":1})
创建索引后,为了验证我们使用使用了索引,可以使用 explain 命令:
>db.users.find({tags:"cricket"}).explain()
1.5.2 索引子文档字段
假设我们需要通过city、state、pincode字段来检索文档,由于这些字段是子文档的字段,所以我们需要对子文档建立索引。
为子文档的三个字段创建索引,命令如下:
>db.users.createIndex({"address.city":1,"address.state":1,"address.pincode":1})
1.6 全文索引
示例文档:
{
"post_text": "enjoy the mongodb articles on test",
"tags": [
"mongodb",
"test"
]
}
创建索引:
db.posts.ensureIndex({post_text:"text"})
使用全文索引
现在我们已经对 post_text 建立了全文索引,我们可以搜索文章中的关键词 test:
>db.posts.find({$text:{$search:"test"}})
删除全文索引
删除已存在的全文索引,可以使用 find 命令查找索引名:
>db.posts.getIndexes()
通过以上命令获取索引名,本例的索引名为post_text_text,执行以下命令来删除索引:
db.posts.dropIndex("post_text_text")
1.7 索引限制
- 额外开销
每个索引占据一定的存储空间,在进行插入,更新和删除操作时也需要对索引进行操作。所以,如果很少对集合进行读取操作,建议不使用索引。 - 内存(
RAM
)使用
由于索引是存储在内存(RAM
)中,应该确保该索引的大小不超过内存的限制。
如果索引的大小大于内存的限制,MongoDB
会删除一些索引,这将导致性能下降。 - 索引键限制
从2.6版本开始,如果现有的索引字段的值超过索引键的限制,MongoD
B中不会创建索引。 - 插入文档超过索引键限制
如果文档的索引字段值超过了索引键的限制,MongoDB
不会将任何文档转换成索引的集合。与mongorestore和mongoimport工具类似。 - 最大范围
集合中索引不能超过64
个
索引名的长度不能超过128
个字符
一个复合索引最多可以有31
个字段 - 查询限制
索引不能被以下的查询使用:- 正则表达式及非操作符,如
$nin
,$not
, 等。 - 算术运算符,如
$mod
, 等。 $where
子句
- 正则表达式及非操作符,如