mongodb索引讲解与优化
语句集合
语句 | 功能 | 备注 |
---|---|---|
db.name. getIndexes() | 查询索引 | |
db.name.totalIndexSize() | 查询索引大小 | |
db.name.dropIndex("indexName") | 删除索引 | |
db.name.dropIndex(‘*’) | 删除name集合中的所有索引 | _id索引不会删除 |
没有修改索引的方法 | 如果想想修改索引 | 先删除旧索引,再重新创建索引 |
db.name.ensureIndex() | 创建索引 |
索引种类
种类 | 解释 | 备注 |
---|---|---|
默认索引 | Mongodb每个collection都会有一个默认主键_id,这个不能删除、也不会更名。当collection创建后,系统会自动创建一个”id”的索引,这个也是无法删除与更名的 | |
单列索引 | 在单个栏位上创建的索引 | eg:需要对Mail的read创建升序索引:db.Mail.ensureIndex({‘read’:1}) |
组合索引 | 对多个键创建的索引 | eg:需要对Mail的user与folderId创建降序索引:db.Mail.ensureIndex({‘user’:-1,’folderId’:-1}) |
子文档索引 | 可以为内嵌文档的键创建索引,这种与普通索引没有什么区别 | eg:需要对Mail中的attachments下的filename创建索引: db.Mail.ensureIndex({‘attachments.filename’:1}) 注意:attachments.filename必须位于’’之中,否则会报错 |
唯一索引 | 唯 一索引可能确保collection的每一个document指定的键的唯一性。当文档不存在指定键时,会被认为键值是“null”,所以“null”也 会被认为是重复的,所以一般被作为唯一索引的键,最好都要有键值对 | 要保证Mail中每个用户的mailfilename的唯一性:db.Mail.ensureIndex({‘user’:1,‘filename’:1},{name:’index1’,‘unique’:true}) 当为已有的collection增加唯一索引时,可能会有数据已经重复了。有时候可能希望将所有包含重复的文档都删除,可能在创建唯一索引时,使用dropDups选项: db.Mail.ensureIndex({‘user’:1,‘filename’:1},{‘unique’:true,’dropDups’:true}) 这个会将重复的数据只保留一份,不过有点鲁莽,如果数据很重要的话,建议不好这样做。 注意了: Insert并不检查文档是否插入过,所以确保数据的唯一性,可能要用安全模式插入才行。这样,在插入时,如果有重复就会有错误提醒 |
Sparse索引 | Sparse index解决索引文件过大的问题,有时候我们要索引的某个属性并非是所有记录都有,普通的索引是将所有的记录都包含进来,而sparse索引则仅包含含 有这个属性的记录,它不会对该项值为空的行作索引。这样就大大减小了某些列的索引大小。目前的限制是,sparse index只能包含一个属性。 | eg:在Mail中有个标签属性labels,这个属性是唯一的,且有值的情况也不多,这种情况就最适合用sparse索引 了,创建索引的命令为: db.Mail.ensureIndex({labels:1},{sparse:true}) |
Covered 索引 | 如果你查找的值正好是在索引中,则可以直接返回索引中存的值,而不用到数据文件中查找。(这个在传统关系型数据库中也有实现),不过,必须满足以下条件: 1:必须提供准备的返回字段,以便可以直接从索引库中查询 2:必须明确地排除使用_id字段{_id:0}当用explain时,当indexOnly=true,表示有用到covered index |
// do a login with a covered index, returning the users roles/groups > db.users.ensureIndex( { username : 1, password : 1, roles : 1} ); > db.users.save({username: "joe", password: "pass", roles: 2}) > db.users.save({username: "liz", password: "pass2", roles: 4}) > db.users.find({username: "joe"}, {_id: 0, roles: 1}) { "roles" : 2 } > db.users.find({username: "joe"}, {_id: 0, roles: 1}).explain() { "cursor" : "BtreeCursor username_1_password_1_roles_1", ... "indexOnly" : true, ... } |
索引触发条件
索引命中:
假设索引为:
{a:1,b:1,c:1,d:1}:
实际上是有了下列索引
{a:1},{a:1,b:1},{a:1,b:1,c:1},{a:1,b:1,c:1,d:1}
但是使用{b:1}、{a:1,c:1}等索引的查询是会被优化的,只有使用索引前部的查询才能使用该索引。
Mongodb的查询优化器会重排查询项的顺序,以便命中索引,比如:查询{x:’a’,y:’b’}的时候,如果已有了{y:1,x:1}的索引,mongodb也会自己找到并命中的。
创建索引的缺点是每次插入、更新与删除时都会产生额外的开销,这是因为数据库不但需要执行这些操作,还是处理索引,因些,要尽量可能少创建索引。每个集合默认的最大索引个数为64个。
查询时,不要使用$ne or $nin,这样不能命中索引
使用explain查看
db.collection.find(query).explain();
返回的信息如下
{“cursor” : “BasicCursor”,
“indexBounds” : [ ],
“nscanned” : 57594,
“nscannedObjects” : 57594,
“nYields” : 2 ,
“n” : 3 ,
“millis” : 108,
“indexOnly” : false}
现实结果可以得知cursor的类型,DB扫描的数据数,返回的数据数,还有执行的毫秒数。
“cursor” : “BasicCursor”:
命中的索引,当为BasicCursor时表示没有命中任何索引
indexBounds: 所使用的索引,被设置为表示为索引扫描的关键边界。
nscanned – 扫描的数据条数。
nscannedObjects – 扫描对象的数。
nYields – 查询所产生的锁的个数。
isMultiKey- MongoDB中提供了可以自动索引数组对象的值
If true, a multikey index was used.
n- 返回文档的数量
millis- 数据库中执行查询的时间
indexOnly – 是否使用了covered index。