MongoDB中的性能分析及索引操作
- 性能分析函数explain();
- 语法:cursor.explain(verbose),verbose为true或者1的时候会输出所有的执行计划和旧的执行计划;
- 一般是跟在find()操作后使用(eg:db.mycoll.find().explain()),它的执行速度决定于实际查询的速度,尽管explain()会额外生成一系列候选的执行计划,但是跟实际查询的性能相差不大;
- explain函数的输出结果;
- explain()函数输出结果含义:
- cursor:查找使用的cursor类型和索引名称;
- isMultiKey:是否是联合索引;
- n:返回记录的个数;
- nscannedObjects:遍历的文档对象的个数;
- nscanned:遍历的文档的个数;
- nscannedObjectsAllPlans: <num>;
- nscannedAllPlans: <num>;
- scanAndOrder: <boolean>;
- indexOnly: <boolean>;
- nYields: <num>;
- nChunkSkips: <num>;
- millis:消耗的时间,单位是ms;
- indexBounds:索引的范围,如果为空表示没有用到索引;
- llPlans:产生的所有的候选的执行计划;
- oldPlan:旧的执行计划;
- server:主机名和端口号<host:port>;
- 创建/删除索引,及前后效率的对比;
- 创建索引语法:db.mycoll.ensureIndex(keypattern[,options]);
- keypattern:是索引的键;
- options:可以取name,unique,dropDups,sparse等值;
- 只有在某个列上没有索引才会创建,如果存在索引的话就不再创建;
- 默认创建的是b-tree索引;
- 可以在子文档上创建索引:db.mycoll.ensureIndex({“object.attritude”:1});
- 没有创建索引时,查找name=index10000的效率:db.index.find({“name”:”index10000″}).explain();使用的是BasicCursor即没有索引,扫描了10w条记录后返回1条记录,消耗了192ms;
- 在name列创建一个名为idx_index_name的索引:db.index.ensureIndex({name:1}, {name:”idx_index_name”}),如果不指定第二个参数中的name的话,则系统会自动生成一个索引的名称;
- 查看创建索引后的效率,发现使用了Btree索引,一共扫描一条记录,返回1条记录,并且瞬间返回;
- 删除索引语法:db.mycoll.dropIndex(index),可以根据名称删除索引,或者根据创建时指定的键值;
- db.mycoll.dropIndex(“indexName”):根据索引名称删除;
- db.mycoll.dropIndex({ “indexKey” : 1 }):根据key值删除索引;
- 如果要删除某个集合下所有的索引,则使用db.mycoll.dropIndexes(),但是无法删除系统自动创建的基于_id列的索引,它由数据库自己维护;
- 重建索引:db.mycoll.reIndex(),是把原来的索引删掉后重建;
- 创建索引语法:db.mycoll.ensureIndex(keypattern[,options]);
- 唯一索引:
- 语法:db.mycoll.ensureIndex(keypattern, {unique:true});
- 创建一个基于name列的唯一索引unq_index_name:db.index.ensureIndex({name:1}, {name:”unq_index_name”, unique:true});
- 如果某一个列上已经存在的重复值,在这样的列上创建唯一索引的话可以使用dropDups选项,这样系统会保留第一条记录,删除剩下重复的记录:db.mycoll.ensureIndex(keypattern, {unique:true, dropDups:true});
- 如果某一个列是唯一列,插入数据时没有插入此列的话会保存一个null值,一个唯一列中只能有一个null值;(这点与关系型数据库不同,关系型数据库中唯一列中可以保存null值,但是在mongodb中null值作为了一个值来比较)
- 组合索引:
- 语法与普通索引相同,只是需要多指定几个列:db.mycoll.ensureIndex({key1:value1, key2:value2, …});
- 键后面的数字表示索引的存储顺序,其中1表示升序,-1表示降序.在随机访问的时候意义不大,但是在排序或者是范围查询时很重要;
- 如果在a,b,c三列上创建了这索引,则以a,ab,abc开头的条件都可以使用到此索引;
- 稀疏索引:
- Sparse indexes only contain entries for documents that have the indexes field, any document that is missing the field is not indexes;
- By contrast, non-sparse indexes contrain all documents in collection, and store null values for documents that do not contrain the indexes field;
- 语法:db.mycoll.ensureIndex(keypattern, {sparse:true});
- 稀疏索引与非稀疏索引的对比;
- hint:
- 查询优化器会选择最优的执行计划,而且第一次执行后的执行计划将会被保存;如果需要使用自己指定的查询方案的话可以使用hint;
- 语法:cursor.hint(index);
- db.mycoll.find().hint(“index_name”):通过指定索引名称来实现hint;
- db.mycoll.find().hint({key:value}):通过指定创建索引时的key的顺序来实现hint,可以之前通过db.mycoll.getIndexes()查看;
- 查看hint的性能:db.mycoll.find().hint(index).explain();
- 注意事项:
- MongoDB中的索引是大小写敏感的;
- 当更新对象时,只有在索引上的这些key发生变化才更新,所以提高了性能;当对象增长了或者移动时,所有的索引都必须更新,会很慢;
- 索引的信息会保存在system.indexes集合中,运行db.system.indexes.find()可以查看这些数据;
- 索引的字段的大小限制目前是800bytes,大于之后可以在这个字段上创建索引,但是该字段不会被索引;
- 如果数据集合比较小(4M),可以联合使用limit()和sort()函数而不需要创建索引来查询数据;
———————- 10w条测试数据 ———————-
db.index.remove()
for(var i = 0; i < 100000; i++){
db.index.insert({name:”index”+i, age:i})
}
.png)
———————- 10w条测试数据 ———————-
———————- 稀疏索引与非稀疏索引的对比 ———————-
— 1.测试数据;
db.sparse.insert({name:”sparse1″, age:20})
db.sparse.insert({name:”sparse2″})
db.sparse.find()
.png)
— 2.在age列创建一个稀疏索引;
db.sparse.ensureIndex({age:1}, {name:”idx_sparse_age”, sparse:true})
db.sparse.getIndexes()
.png)
— 3.查看数据,稀疏索引中不包含列为null的文档,只有稀疏索引中的文档才会被返回;
db.sparse.find()
db.sparse.find().sort({age:1})
db.sparse.find({name:{$ne:0}})
.png)
— 4.删除稀疏索引,并创建一般的索引;
db.sparse.dropIndex(“idx_sparse_age”)
db.sparse.ensureIndex({age:1}, {name:”idx_sparse_age”})
db.sparse.getIndexes()
.png)
— 查看数据,非稀疏索引中包含了列为null的文档;
.png)
———————- 稀疏索引与非稀疏索引的对比 ———————-