索引的类型

单字段索引

复合索引

其他索引类型

  • 哈希索引:是指按照某个字段的hash值来建立索引,目前主要用于 MongoDB Sharded Cluster 的 Hash 分片,hash索引只能满足字段完全匹配的查询,不能满足范围查询等。

  • 地理位置索引:能很好的解决 O2O 的应用场景,比如『查找附近的美食』、『查找某个区域内的车站』等。

  • 文本索引:能解决快速文本查找的需求,比如有一个博客文章集合,需要根据博客的内容来快速查找,则可以针对博客内容建立文本索引。

索引的操作

测试数据

  1. for (var i = 1; i <= 100; i++) {
  2. db.xyj.insert({
  3. name: 'taibai' + i,
  4. num: i
  5. });
  6. }

创建匿名索引


查找 num: 100 文档的过程分析

  1. db.xyj.find({num: 100}).explain(true)
  2. 返回信息:
  3. "stage" : "COLLSCAN", 意思为全表扫描
  4. "executionTimeMillis" : 144 查询时间

创建匿名索引

1:代表正序, -1:代表 倒序

  1. db.xyj.createIndex({num: 1})
  2. 返回信息:
  3. {
  4. "createdCollectionAutomatically": false,
  5. "numIndexesBefore": 1, // 添加本次索引之前的索引数
  6. "numIndexesAfter": 2, // 添加本次索引之后的索引数
  7. "ok": 1
  8. }

建立索引后再次查找

  1. db.xyj.find({num: 100}).explain(true)
  2. 返回信息:
  3. "stage" : "IXSCAN", // 通过扫描索引进行查找
  4. "indexName" : "num_1", // 如果没有指定索引名称的话, 默认格式为 ‘字段_1’ 或者 ‘字段_-1’
  5. "executionTimeMillis" : 0, // 本次执行时间的毫秒数为 0ms

创建命名索引

如果没有指定索引名称的话, 默认格式为 fieldName1 或者 fieldName-1,如果想要自定义索引名称的话,可以在创建的时候指定名称,如下:

  1. db.xyj.createIndex({name: 1}, {name:' myIndexName'})

查询索引

v:表示版本号,key:在那个字段创建了索引,是升序还是降序的,name:索引名称,ns:哪个数据库的集合下

  1. db.xyj.getIndexes()
  2. 返回信息:
  3. [
  4. {
  5. "v": NumberInt("2"),
  6. "key": {
  7. "_id": NumberInt("1")
  8. },
  9. "name": "_id_",
  10. "ns": "test.xyj"
  11. },
  12. {
  13. "v": NumberInt("2"),
  14. "key": {
  15. "num": 1
  16. },
  17. "name": "num_1",
  18. "ns": "test.xyj"
  19. }
  20. ]

指定需要使用的索引

hint:指定强制使用哪个索引

  1. db.xyj.find({num: "100"}).hint({num:1}).explain(true)

创建复合索引

查询的条件不止一个,需要用复合索引

  1. db.xyj.createIndex({name:1, num:1});

创建 TTL(过期)索引

mongodb 也可以像 redis 一样给文档设置过期数据,建立 ttl 索引,这里设置了10 秒钟的过期时间,10 秒钟之后过期

  • 索引字段的值必须 Date 对象,不能是其它类型比如时间戳
  • 删除时间不精确,每60秒跑一次,会删除所有过期数据,同时删除也要时间,所以有误差。
    1. db.classTwo.insert({time:new Date()});
    2. db.classTwo.createIndex({time: 1}, {expireAfterSeconds: 10});

    创建全文索引


    测试数据

    1. db.xyj.insertMany([
    2. {"name": "Lily", "content": "I am a girl"},
    3. {"name": "Tom", "content": "I am a boy"},
    4. {"name": "Carl", "content": "I do not know boy girl"}
    5. ])

    创建全文索引

    1. db.xyj.createIndex({content: 'text'})

    使用全文索引

最大的问题,全文索引不支持中文。准确的来说,支持中文的能力没有想象中强大。

  1. // 查找包含 ‘girl’ 的文档
  2. db.xyj.find({$text: {$search: 'girl'}})
  3. // 查找包含 ‘girl’ 或者 ‘boy’ 的文档(多次查找是 与 的关系)
  4. db.xyj.find({$text: {$search: 'boy girl'}})
  5. // 查找仅包含‘girl’ 不包含‘boy’的文档
  6. db.xyj.find({$text: {$search: 'girl -boy'}})
  7. // 就是要查找包含 ‘girl boy’ 字符的文档(需要转义)
  8. db.xyj.find({$text: {$search: '\"boy girl\"'}})

二维(地理位置)索引


测试数据

  1. db.dili.insertMany([
  2. {"gis": [ 1, 1 ]},
  3. {"gis": [ 1, 2 ]},
  4. {"gis": [ 1, 3 ]},
  5. {"gis": [ 2, 1 ]},
  6. {"gis": [ 2, 2 ]},
  7. {"gis": [ 2, 3 ]},
  8. {"gis": [ 3, 1 ]},
  9. {"gis": [ 3, 2 ]},
  10. {"gis": [ 3, 3 ]}
  11. ]);

创建二维索引

  1. db.dili.createIndex({gis:'2d'})

使用二维索引

  1. // 查询距离`[1,1]`最近的四个点
  2. db.dili.find({gis:{$near: [1,1]}}).limit(4)
  3. // 查询以点`[1,2]`和点`[3,3]`为对角线的正方形中的所有的点
  4. db.dili.find({gis: {$within: {$box: [[1,2], [3,3]]}}})
  5. // 查出以`[2,2]`为圆心,以`1`为半径为规则下圆心面积中的点
  6. db.dili.find({gis: {$within: {$center: [[2,2], 1]}}})

删除索引

db.集合名称.dropIndex(索引名称或者创建时的条件)

  1. // 按名称删除
  2. db.xyj.dropIndex("age_1")
  3. // 按创建条件删除
  4. db.xyj.dropIndex({age:1})
  5. // 删除所有索引,自带的这个 id 的索引是不会删除的
  6. db.xyj.dropIndexes()