MongoDB 索引介绍

本贴最后更新于 2525 天前,其中的信息可能已经时过境迁

一、索引的创建和使用

1.1 索引创建和删除:

创建索引时的格式:db.collection.ensureIndex({param}, {param})
其中,第二个参数是索引的属性。

索引属性:
比较重要的属性有:

  1. 名字:db.collection.ensureIndex({}, {name, ""})
    说明:默认索引名字是“字段名_类型”,名字可以进行自定义设置

  2. 唯一性:db.collection.ensureIndex({}, {unique, true/false})

     db.testIndex.ensureIndex({a:1,b:1}, {unique: true})
    

    保证唯一性,类似于设定 a 字段与 b 字段为联合主键

  3. 稀疏性:db.collection.ensureIndex({}, {sparse, true/false})
    mongodb 默认创建的索引都是不稀疏的
    用于对某些不存在建立索引字段的数据元素,不对其建立索引。减少索引占用的空间,提高插入速度。

  4. 是否定时删除:db.collection.ensureIndex({}, {expireAfterSeconds: }),具体查看过期索引
    删除索引可以通过其索引名进行:

     db.user_collection.dropIndex("testIndexName")
    

1.2 索引种类:

1.2.1 _id 索引。

_id 索引是绝大多数集合默认建立的索引。
对于每个插入的数据,MongoDB 都会自动生成一条唯一的_id 字段。

1.2.2 单键索引。

单键索引是最普通的索引。
与_id 索引不同,单键索引不会自动创建。

db.user_collection.ensureIndex({x:1}) //创建索引,为1正向排序,为-1逆向排序

1.2.3 多键索引。

与单键索引创建形式相同,区别在于字段的值。
单键索引:值为一个单一的值,例如字符串,数字或日期。
多键索引:值具有多个记录,例如数组。

1.2.4 复合索引。

查询条件不只有一个时,就需要建立复合索引。

db.testCollection.ensureIndex({x:1,y:1})

1.2.5 过期索引。

是在一段时间后会过期的索引。
在索引过期后,相应的数据会被删除。
适合存储一些在一段时间之后会失效的数据比如用户的登录信息、存储的日志。
存储在过期索引字段的值必须是指定的时间类型。必须是 ISODate 或者 ISODate 数组,不能使用时间戳,否则不能被自动删除。
若是 ISODate 数组,则按照最小的时间进行删除。
过期索引不能是复合索引。
删除时间不精确,因删除过程是由后台程序每 60s 跑一次,且删除需要时间,故存在误差。

db.user_collection.ensureIndex({time:1}, {expireAfterSeconds:30}) //设定过期索引。
db.user_collection.insert({time: new Date()}) //此条数据因过期索引的设置,在30s后会被删除。(有误差)
db.user_collection.insert({time:1}) //此条数据不会受过期索引的影响被删除。因为该字段的值不是指定的时间类型。

1.2.6 全文索引。

对字符串与字符串数组创建全文可搜索的索引。
对单个字段建立索引:db.articles.ensureIndex({key:”text”});
对多个字段建立索引:db.articles.ensureIndex({key_1:”text”, key_2:”text”});
对所有字段建立索引:db.articles.ensureIndex({“$**”:”text”});

使用:

搜索关键字 coffee :

db.articles.find({$text:{$search:”coffee”}});

或查询,搜索关键字 aa 或 bb 或 cc :

db.articles.find({$text:{$search:”aa bb cc”}});

-表示排除,搜索包含关键字 aa 或 bb,并不包含 cc :

db.articles.find({$text:{$search:”aa bb -cc”}});

加引号,表示并且,搜索包含 bb 或包含 cc 或两个都不包含,并且包含 aa 的:

db.articles.find({$text:{$search:”\“aa\” bb cc”}});

表示包含 aa 且包含 bb 且包含 cc 的:

db.articles.find({$text:{$search:"\"aa\" \"bb\" \"cc\""}}) 

全文索引相似度:$meta操作符:{score: {$meta: “textScore”}}

写在查询条件后面可以返回结果的相似度,与 sort 一起使用,可以达到很好的实用效果。

db.articles.find({$text:{$search:"aa bb"}},{score:{$meta:"textScore"}})
db.articles.find({$text:{$search:"aa bb"}}, {score: {$meta: "textScore"}}).sort({score: {$meta: "textScore"}})

全文索引使用限制:

  1. 每次查询,只能指定一个 $text 查询。
  2. text查询不能出现在nor 查询中。
  3. 查询中如果包含了 $text,hint(指定使用某索引)不再起作用。
  4. 全文索引不支持中文。

1.2.7 地理位置索引。

将一些点的位置存储在 MongoDB 中,创建索引后,可以按照位置来查找其他点。
子分类:
2d 索引,用于存储和查找平面上的点。
2dsphere,用于存储和查找球面上的点。

一般查找方式有两种:

  1. 查找以某点为中心点,一定距离内的点。
  2. 查找包含在某区域内的点。

一般可以用在打车、电商查找一定范围内的商家等方面。也可用于查找一定范围内的项目等。

2d 索引:

创建方式:

db.collection.ensureIndex({w:”2d”})

位置表示方式:[经度,纬度]
取值范围:经度[-180, 180],纬度[-90, 90]
查找方式:

  1. 查找以某点为中心点,一定距离内的点。
    a. $near 查询

    查询距离某个点最近的点。

     db.location.find({w:{$near: [1,1]}}) 默认选中前100个
     db.location.find({w:{$near: [1,1], $maxDistance:10}})
    

    maxDistance,但没有minDistance

    b. geoNear 查询
    $box:矩形使用
    表示方式:{$box:[[,], [,]]}
    $center:圆形使用
    表示方式:{$center:[[,], r]}
    $polygon:多边形使用
    表示方式:{$polygon:[[,],[,],[,]]}

     db.location.find({w:{$geoWithin: {$box: [[0,0],[3,1]]}}}) //查询在[0,0]~[3,1]的矩形内的点
     db.location.find({w:{$geoWithin: {$center: [[0,0],3]}}}) //查询在以[0,0]为圆心,半径为3的圆形内的点
     db.location.find({w:{$geoWithin: {$polygon: [[0,0],[0,1],[1.1,1.1]]}}}) //查询在多边形内的点
    
  2. 查找包含在某区域内的点。

    a. $geoWithin 查询

     db.runCommand({geoNear:,
       near: [x,y],
       minDistance, (对2d索引无效)
       maxDistance,
       num:
     })
    

    查询结果中,stats 中:
    time—花费的时间
    maxDistance—最大距离
    avgDistance—平均距离
    results 中:
    dis—该点距离所选点的距离
    obj—查找到的文档

2dsphere 索引:

球面地理位置索引

创建方式:

db.collection.ensureIndex({w:”2dsphere”})

二、索引构建情况分析

索引好处:加快索引相关的查询。

索引坏处:增加磁盘空间消耗,降低写入性能。

2.1 mongostat 工具介绍

输入命令:

mongostat –h 127.0.0.1:12345

显示结果如下:

16c283f6392d46afb802e3be40bafe63-image.png

实际反映性能最直观的是 qr|qw,读队列和写队列,若对应的值比较高,则说明有比较严重的性能问题。
idx miss% 表示查询没有应用索引的情况,若数据量较小,不太看得出来。若 idx miss% 较高,很容易导致 qr 较高。

2.2 profile 集合介绍

开启 profile 会记录下操作的详情。可用于分析操作。
查看当前 profile 级别:

db.getProfilingStatus()

得到结果如下:

{“was”: 0, “slowms”: 100}

profile level 有 3 个级别(was 属性):
0--profile 是关闭的,不会记录任何操作。
1--以 slowms(毫秒数)为阀值,会记录超过 slowms 的操作。
2--会记录任何操作。

设置 profile 级别:

db.setProfilingLevel(2)

profile 会记录在 system.profile 中:

查询 system.profile 中最近一条记录:

db.system.profile.find().sort({$natural: -1}).limit(1)

结果示例如下图:

e6370f63af2c4b8fba27afb75c8bf640-image.png

op—操作类型
ns—命名空间,数据库名.集合名
query—find 的字符串
orderby—sort 的条件
cursorid—多次 getmore 是保存的游标
ntoreturn—返回的数据条数
ntoskip—跳过的数据数目
nscanned—扫描的索引/实体数目
nscannedObjects—扫描的实体数目,一般 nscanned>=nscannedObjects
timeLockedMicros—锁的占用情况(单位:微秒)

profile 的开启会记录每次操作的详情,故会影响 mongodb 的使用性能,所以 profile 的使用场景多是新系统上线前的测试阶段。

2.3 日志介绍

配置 mongo.conf 文件:

添加属性 verbose=vvvvv

通过使用 verbose 控制日志详细程度,分 1~5 个 v,v 越多,详细度越高。

2.4 explain 分析

可以使用 explain 查看操作详情。可以用来查看特定索引的使用情况。
如:

db.users.find().explain()
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    90 引用 • 59 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...