for(i=0;i<100000;i++){
db.users.insert( {"i":i, "username":"user"+i, "age":Math.floor(Math.random()*120), "created":new Date()} );
}
explain()函数查看MongoDB在执行查询的过程中所做的事情,执行计划
建立索引db.users.ensureIndex({username:1})
db.currentOp()或者检查mongod的日志来查看索引创建的进度
建立复合索引db.users.ensureIndex({age:1,username:1})
三种主要方式会使用到复合索引
1、点查询, db.users.find({"age":21}).sort({"username":-1}),非常高校,定位到正确年龄且不需要结果排序
2、多值查询 ,db.users.find({"age":{"$gte":21,"$lte":30}})
3、多值查询,db.users.find({"age":{"$gte":21,"$lte":30}}).sort({"username":1}),需要在内存中先对结果进行排序,然后再返回。如果结果集大于32mb,mongod就会出错,所以不需要对数据进行排序,可以将排序键放在第一位并限定查询结果,如limit(1000)
Hint强制mongodb使用某个特定的索引。
索引本质上是树,最小的值在最左边的叶子上,如果程序需要使用最近数据机会多,mongodb只需在内存中保留这棵树最右侧的分支。类似这样的索引是右平衡的。
复合索引
1、选择键的方向,基于多个查询条件进行排序,方向才是比较重要的
2、使用覆盖索引,只查询索引中包含的字段,但是数组做索引则永远无法覆盖查询
3、隐式索引,只使用索引前缀的查询才能受益
$操作符如何使用索引
1、低效率的操作符
$where
$exists ,不存在的字段和null字段的存储方式是一样的,需遍历每一个文档检查这个值是否真的为null
$ne,如果不等于的结果非常多,不得不扫描整个索引
$not,大多数会退化为进行全表扫描
$nin,总是进行全部扫描
2、范围
先使用第一个索引键进行精确匹配,再使用第二个索引范围在结果集内部进行搜索
3、OR查询
or实际上是执行两次查询然后将结果集合并,所以尽可能使用$in而不是$or
索引对象和数组
1、索引嵌套文档,可以对嵌套文档本身建立索引,也可以对嵌套文档的某个字段建立索引,对整个子文档建立索引,只会提高整个子文档的查询速度,无法对文档的某个字段的查询使用索引
2、索引数组,对数组建立索引,实际上是对数组的每一个元素建立一个索引条目,所以代价比单值索引高:对于单次插入、删除或者更新
3、多键索引
索引基数
====================
使用explain()和hint()
explain()放在最后,db.users.find({"age":42}).explain();
hint()强制使用某个索引
查询优化器,如果一个索引能够精确匹配一个查询,那么查询优化器就会使用这个索引,可能会有多个索引适合你的查询。mongodb会从这些可能的索引子集中为每次查询计划选择一个,这些查询计划是并行执行的,最早返回100个结果的就是胜者,其他的查询计划就会被中止。并查询计划会被缓存,知道集合数据发生了比较大的变动
=====================
何时不应该使用索引
结果集在原集合中所占的比例越大,索引的速度就越慢
{"natural":1}强制数据库做全表扫描:返回的结果按照磁盘上的顺序排列的
=====================
一、索引类型
唯一索引{"unique":true}
db.users.ensureIndex({"username":1},{"unique":true})
对于唯一索引,null的值也只能插入一个
索引储桶的大小是有限制的,索引条目不能超出限制,所有的字段都必须小于1024字节才能包含到索引里,超出8kb大小的键不会受到唯一索引的越俗:可以插入多个同样的8kb长的字符串
1、复合唯一索引
GirdFS是MongoDB中存储大文件的标准方式{"files_id":1,"n":1}
2、去除重复
创建索引时使用“dropDups”选项,如果遇到重复的值,第一个会被保留,之后的重复文档会被删除。
db.users.ensureIndex({"username":1},{"unique":true,"dropDups":true})
二、稀疏索引——sparse选项就可以
unique和sparse组合使用,就可以使用在存在null的字段上了
sparse也可以单独使用,对于大多数有x字段,有些没有的情况,用db.foo.find({"x":{"$ne":2}})如果有稀疏索引,则不返回没有x字段的文档,如果需要的话,可以用hint()强制全表扫描
====================
索引管理
所有的数据库索引信息都存储在system.indexs集合中。这是保留集合,不能插入或者删除文档,只能通过ensureIndex或者dropIndexes对其进行操作。
可以执行db.collectionName.getIndexes()来查看给定集合上的所有索引信息
一、标识索引
Keyname1_dir1_keyname2_dir2_……_keynameN_dirN,长度有限制,可以自定义索引名称,调用getLastError可以知道索引是否成功创建或者失败的原因
二、修改索引
dropIndex命令删除不再需要的索引 de.people.dropIndex("x_1_y_1"),用name来指定需要删除的索引
background选项可以指定,如果有新的数据库请求需要处理,创建索引的过程就会暂停一下
在已有的文档上创建索引会比新创建索引再插入文档快一点。