---------------------MongoDB索引---------------------
1、索引简介:
1、扩展索引
创建索引时要考虑如下问题:
会做什么样的查询?其中那些键需要索引?
每个键的索引方向是怎样的?
如何应对扩展?有没有种不同的键的排列可以使用常用数据更多的保留在内存中?
例:一个存储用户状态的表
db.status.ensureIndex({"user":1,"date":1}):用户在前
db.status.ensureIndex({"date":1,"user":1}):时间在前
2、索引内嵌文档中的键
为内嵌文档的键建立索引和为普通的键创建索引没有什么区别。
db.blog.ensureIndex({"comments.date":1})
3、为排序创建索引
随着集合的增长,需要针对查询中大量的排序做索引。如果对没有索引的键调用sort,MongoDB需要将所有数据提取到内存来排序。因此,可以做无索引排序是有个上限的,那就是不可能在内存里面做T级别数据的排序。一旦集合大到不能在内存中排序,MongoDB就会报错。
按照排序来索引以便让MongoDB按照顺序提取数据,这样就能排序大规模数据,而不必担心用过内存。
4、索引名称
集合中的每个索引都有一个字符串类型的名字,来唯一标识索引,服务器通过这个名字来删除或者操作索引。索引名类似keyname1_dir1_keyname2_dir2...keynameN_dirN这种形式,其中keynameX代表索引的键,dirX代表索引的方向(1或-1).要是索引的键特别多,这样命名就略显笨拙。
ensureIndex创建索引是可以进行名字的创建工作
db.foo.ensureIndex({"a":1,"b":2,"c":3...,"z":1},{"name":"alphabet"})
2、唯一索引:
1、唯一索引可以保存集合的每一个文档的指定键都有唯一值。
db.集合名.ensureIndex({"username":1},{"unique":true})
2、消除重复:当为已有的集合创建索引,可能有些值已经有重复了。若是真的发生这种情况,那么索引的创建就会失败。有些时候,可能希望将所有包含重复值的文档都删掉。dropDups选项就可以保留发现的第一个文档,而删除接下来的有重复值的文档。
db.集合名.ensureIndex({"username":1},{"unique":true,"dropDups":true})
3、复合唯一索引
创建复合唯一索引的时候单个键的值可以相同,只要所有键的值组合起来不同就好。
3、使用explan和hint
1、explain:
1、explain是一个非常有用的工具,会帮助你获得查询方面诸多有用的信息。只要对游标调用该方法,就可以得到查询细节。explain会返回一个文档,而不是游标本身,这是与多数游标方法不同之处。
db.集合名.find().explain()
explain会返回查询使用的索引情况(如果有的话),耗时及扫描文档数的统计信息。
例:
db.people.find({"age":18}).sort({"username":1}):
这是就搞不太准确数据库到底用没用已经创建的索引,或者到底效率如何。使用explain就会得到当前查询所使用的索引,消耗了多少时间,以及数据库需要扫描多少文档才能得到结果。
2、对应参数的分析:
1、"cursor":"BasicCursor":这说明查询没有使用索引/"cursor":"BasicCursor age_1":这说明查询使用了索引
2、"nscanned":64:这个数字代表数据库查询找了多少个文档。大家都想让这个数字尽可能地接近返回结果的数量。
3、"n":64:这个代表返回文档的数量。
4、"millis":0:这个毫秒数表示数据库执行查询的时间。0是非常理想的成绩。
2、hint:
如果发现MongoDB用了非预期的索引,可以用hint强制使用某个索引。
例:
db.c.find({"age":14,"username":/.*/}).hint({"username":1,"age":1})
4、索引的管理:
1、索引的元信息存储在每个数据库的system.indexes集合中。这是一个保留集合,不能对其插入或删除文档。操作只能通过ensureIndex或者dropIndexes进行。system.indexes集合包含每个索引的详细信息,同时system.namespaces集合也含有索引的名字。
2、索引的创建:
语法:
ensureIndex()方法基本语法格式如下所示:
>db.COLLECTION_NAME.ensureIndex({KEY:1})
注:从mongoDB 3.0开始ensureIndex被废弃,今后都仅仅是db.collection.createIndex的一个别名。
语法中 Key 值为你要创建的索引字段,1为指定按升序创建索引,-1即为降序。
例:
db.mongoDBtest.ensureIndex({"name":1,"age":1})
db.mongoDBtest.ensureIndex({"age":1,"name":1})
3、索引的修改:
使用ensureIndex随时可以向现有集合添加新的索引:
db.mongoDBtest.ensureIndex({"username":1},{"background":true})
建立索引既耗时也费力,还需要消耗很多资源。使用{"background":true}选项可以使这个过程在后台完成,同时正常处理请求。要是不包括background这个选项,数据库会堵塞建立索引期间的所有请求;堵塞的做法会让索引建立更快,同时也意味着应用在此期间不能应答。即便在后台进行也会对正常操作有些影响,所以最好选在无关紧要的时刻。后台创建索引也会增加些负载,好在不会让服务器停机。
4、索引的删除:
索引没用的时,便可以用dropIndexes加上索引名将其删除。通常,要查一下system.indexes集合来找出索引名,
db.runCommand({"dropIndexes":"mongoDBtest","index":"alphabet"})
要删除所有索引,可以将index的值赋为*:
db.runCommand({"dropIndexes":"mongoDBtest","index":"*"})
注:另外一种删除索引的方式就是删除集合。也会删除_id索引(还有集合中的所有文档)。删除集合的所有文档(用remove的方式)并不影响索引,当有新文档时还是会再生的。
5、地理空间索引
1、复合地理空间索引
还有一种查询变得越来越流行(尤其是随着移动设备的出现):找到离当前位置最近的N个场所。MongoDB为坐标平面查询提供了专门的索引,称作地理空间索引。
创建方式:复合地理空间索引还是用ensureIndex来创建,只不过参数不是1或-1,而是“2d”:
db.map.ensureIndex({"gps":"2d"})
例:
db.star.trek.ensureIndex({"light-years":"2d"},{"min":-180,"max":180})
参考:《MongoDB权威指南》