mongo基础使用-索引

类似书本的目录一样, 为了能够快速定位到某一条数据,数据库也都使用了类似的方法,名为索引。但是索引也有它的副作用, 固然,利用索引能够加快查询, 但是为了维护索引, 不可避免的降低了插入的速度, 但是对于查询比较多的情况下,这点损失我们还是能够接受的。索引的创建是要根据需求来的, 过多的索引, 不仅浪费存储空间, 而且会降低插入速度。索引的使用更加要小心, 有时不适当的查询语句会导致,查询并没有使用索引。不单单是mongo, 这可以说是大多数数据库的共性。

Mongo的索引管理

为了测试, 我们先批量插入一些数据

for(var i = 0; i < 1000000; ++i){
  db.users.insert({
    "i": i,
    "name": "user" + i,
    "age": Math.floor(Math.random() * 120),
    "created": new Date()
  })
}

创建索引

不同于MySQL的索引, mongo的索引是有方向的, value代表了索引的方向, 这个特性在排序的使用很好用。1 代表升序, -1代表降序

普通索引

db.collection.ensureIndex({filedName: value})

复合索引

就是在创建索引的时候同时指定多个字段

注意事项

  1. 索引是区分方向的

    db.users.ensureIndex({"name": 1, "age": 1})db.users.ensureIndex({"name": 1, "age": -1})是两个不同的索引。只有要针对多个字段进行排序时, 索引的方向才是重要的, mongo会自动的翻转索引, 也就是说{"name": 1}{"name": -1}在使用时是一致的。{"name": 1, "age": 1}{"name": -1, "age": -1}也是一致的。

  2. 索引字段要有序

    为了能够更加有效的利用索引, 用于精确匹配的字段应该放在索引的前面, 范围字段放在后面, 这样mongo就能利用精确匹配过滤掉大部分文档, 然后利用之后的索引去再次过滤结果。例如我们要查询name=user10&age>20, 那么我们的索引应该是{"name": 1, "age": 1}, 而不是{"age": 1, "name": 1}

  3. 隐式索引

    如果我们创建一个复合索引{"name": 1, "age": 1, "created": -1}, 当利用{"name": 1}进行排序的时候, 也能够使用前面创建的索引, 注意, 必须是从左往右依次匹配才行, 也就是说{"age": 1}, 这种是不会用到索引的。

唯一索引

类似MySQL的唯一约束, mongo也是具有的, 用来保证一个集合内相同字段值的唯一性

db.ensureIndex({"name": 1}, {"unique": true, "name": index_name})

如此我们就建立了一个唯一索引, 当然类似MySQL 的联合唯一索引mongo也是有的, 只需要指定多个字段即可。通过name属性, 能够手动指定索引的名字。

PS: 在已有文档的集合上创建唯一索引可能会失败 ,原因是相同字段上的值可能并不唯一, 这是可以使用dropDups属性来强制集合唯一, 但这个操作有风险 ,因为无法保证删除的是哪些文档

db.ensureIndex({"name": 1}, {"unique": true, "name": index_name, "dropDups": true})

稀疏索引

不同于关系型数据库中的稀疏索引, mongo的稀疏索引只是单纯的不索引不含有指定键的文档。

例如: 犹豫唯一索引, 会将null看为值, 会导致新的文档插入失败, 这时,我们就可创建唯一稀疏索引

db.ensureIndex({"name": 1}, {"unique": true, "name": index_name, "sparse": true})

TTL索引

db.collection.ensureIndex({"name": 1}, {"expireAfterSecs": 10*60})

如此就创建了一个TTL索引, mongo会每分钟检查一次索引, 并删除过期的文档。这个索引可以用来排序和搜索。

全文索引

地理空间索引

查询索引

db.collection.getIndexes() 用来查看集合已经具有的索引。

使用索引

类似于MySQL, mongo也有explain方法, 去查看索引的使用情况db.users.find({"name": "user100"}).explain()就能查看是否使用了索引, 以及其他的一些详细信息, 包括, 使用的索引, 扫描的文档数据, 结果的数量, 查询用时等等。

低效率的操作符

有一些查询操作, 无法很好的使用索引,或者完全无法使用索引, 这些要尽力去避免。

  1. $where$exists, 都是无法使用索引的, $exists操作, 会遍历每个文档,以确定字段是否存在, $where会同样的遍历每个文档。
  2. 类似MySQL, 在mongo中使用取反的查询操作, 也会导致索引利用效率低下, 或者不会使用索引, 例如$ne, 而$not虽然有时能够使用索引, 但是通常它并不知道该如何利用索引。
  3. $nin, 总是扫描整个集合。

应对以上的查询, 我们只能利用一些带有索引的字段去过滤掉一部分结果, 尽量减少筛选的文档的数量以加快查询的速度。

使用指定的索引

利用mongo的hint() 操作可以指定此次查询使用的索引。

删除索引

db.collection.dropIndex("index_name")