MongoDB基础部分及实现(二)
MongoDB是由C++语言所编写的一种面向文档的非关系型数据库(是一种NoSql数据库实现),也是介于关系型数据库和非关系型数据库之间的数据存储产品,其提供了高性能、高可用、高可拓展及基于分布式存储的数据库,是非关系型数据库中功能最丰富,最类似关系型数据库的一种集合、文档格式的数据库。
l 索引
l 分析
l 聚合
l 监控
一、索引
MongoDB中的索引与RDBMS中的索引原理相同,主要就是当检索索引字段或文档属性数据时,一旦检索到满足条件的数据,数据库引擎会即刻返回结果,不做数据库的全文检索,可以大大提高数据的检索效率。
1、索引语法
在MongoDB中使用索引,我们需要使用ensureIndex()方法,格式如下:
>db.COLLECTION_NAME.ensureIndex({KEY:1,KEY:-1,…},{options})
NOTE:
1代表升序排列
-1代表降序排列
另外,ensureIndex()也可以接受一些可选的功能参数options,具体如下:
参数 | 类型 | 描述 |
background | Boolean | 在后台建立索引,以便建立索引时不会阻止其他数据库操作,默认值为false,代表未在后台创建索引。 |
unique | Boolean | 创建唯一索引,代表创建索引的文档不能出现重复的文档记录,默认值是 false,代表创建非唯一索引。 |
name | string | 索引的名称,如果未指定,MongoDB引擎会生成一个索引字段的名称和排序顺序串联的名字,实际使用时建议指定索引名字,方便后续对索引维护。 |
dropDups | Boolean | 创建唯一索引时,可能有重复文档记录,指定该参数为true时,会删除非第一条文档的其余重复文档。 |
sparse | Boolean | 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档。 |
expireAfterSeconds | integer | 使用TTL可以设置一个时间范围,如果到了此范围,文档被删除。 |
v | index version | 索引版本号。默认的索引版本取决于mongodb 运行的版本。 |
weights | document | 权重是从1到99999范围内的数,表示该字段的意义,相对于其他的索引字段分数比重。 |
default_language | string | 如果您将语言指定为值 "none" ,那么 text search 会使用简单的分词器,没有停止词也没有取词根处理。默认值是english。 |
language_override | string | 如果语言字段没有language字段,而是别的字段,那么在索引创建的时候,使用language_override指向这个字段。 |
注意:
上面的几个参数并非都常用,读者只需要根据实际使用,熟练使用几个即可,例如:background、unique、name、dropDups及sparse。
2、创建使用
我们就以mydb数据库中的post集合为例,在其文档的title和desc连个字段上建立唯一索引,并设置该动作在后台创建,同时指定该索引的名字,具体如下操作:
>db.post.ensureIndex({'title':1,'desc':-1},{background:true,unique:true,name:'idx_post_title_desc'})
结果显示:
那么,如何知道索引是否工作?请继续查看第二部分:分析,该部分就以该索引为例进行分析查询的信息。
二、分析
我们分析第一部分创建的唯一索引,以mydb数据库的集合post查询为例分析并查看结果显示。在MongoDB中,系统提供了explain和hint两种方式来分析查询的信息。
1、explain
在MongoDB中,explain是非常有用的工具,可以帮助获得查询方面很多有用的信息;只要对游标调用该方法,就可以得到查询细节,并且explain会返回一个文档,而不是游标本身,具体如下使用:
>db.post.find({"title":"MongoDB"}).explain()
结果显示:
NOTE:
stage:代表本次查询为索引类型查询;
keyPattern:代表该索引所属的文档字段;
indexName:代表索引的名字;
isUnique:代表该索引为唯一索引;
2、hint
在MongoDB中,可以使用hint操作符强制查询优化器使用指定索引来运行一个查询,这在查询某个索引的性能方面很实用,具体如下:
>db.post.find({"title":"MongoDB"}).hint({"title":1})
{ "_id" :ObjectId("57e10bd076be84c977b7acda"), "title" :"MongoDB", "desc" : "database", "likes": NumberLong(100000), "url" : "http://www.cwteam.com","by" : "cwteam.com" }
接下来,我们使用explain分析上面的查询:
>db.post.find({"title":"MongoDB"}).hint({"title":1}).explain()
结果显示:
NOTE:
这里使用hint强制本次查询使用索引idx_post_title_desc_new。
三、聚合
聚合操作过程中,从多个文档中计算结果并返回,并可以执行各种操作,分组数据返回单个结果。
1、语法格式
在MongoDB中,我们需要使用aggregate()方法来实现聚合的各种操作,具体格式如下:
>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
常用的聚合方法列表如下:
表达式 | 描述 | 实例 |
$sum | 计算并返回集合中满足条件的所有文档的个数。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}]) |
$avg | 计算并返回集合中满足条件的所有文档的平均值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}]) |
$min | 计算并返回集合中满足条件的所有文档的最小值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}]) |
$max | 计算并返回集合中满足条件的所有文档的最大值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}]) |
$push | 插入值到一个文档的数组中,可能有重复数据。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}]) |
$addToSet | 插入值到一个文档的数组中,不会出现重复数据。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) |
$first | 根据分组从源文档中获取的第一个文档。通常情况下,连同以前的一些应用 “$sort”-stage. | db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}]) |
$last | 根据分组从源文档中获取最后的文档。通常,连同以前的一些应用 “$sort”-stage. | db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}]) |
注意:
上面的几个参数并非都常用,读者只需要根据实际使用,熟练使用几个即可,例如:sum、avg、min、max及push。
2、如何使用
这里我们同样以mydb数据库中的post集合为例,数据格式如下:
然后,我们使用方法aggregate()按by分组,并计算各个分组中的文档个数,具体如下操作及显示:
>db.post.aggregate([{$group:{_id:"$by",num_bys:{$sum:1}}}])
{ "_id" : "jakeup.com","num_bys" : 1 }
{ "_id" :"cwteam.com", "num_bys" : 2 }
NOTE:
如上所示,共分两组,一组文档个数为1,另一组文档个数为2。
四、监控
在MongoDB中,其本身提供了两种常用的状态监控工具,分别为mongotop和mongostat。在实际使用MongoDB数据库时,我们需要间隔固定时间检测下所有启动的MongoDB服务的状态,或是当数据操作缓慢及其它问题时,我们最先考虑的是使用它们来测试下当前的实例状态,再而修复问题。
1、mongostat
mongostat工具会间隔固定时间获取并输出mongodb的当前运行状态,一般发现数据库变慢或是其他问题时,首先考虑使用其对实例服务进行侦测。
具体使用如下:
$sudo ./mongostat
输出结果显示:
结果参数说明:
insert/query/update/delete->每秒插入/查询/更新/删除的次数;
getmore->每秒执行getmore的次数;
command->每秒实例执行命令数目;
dirty->是否生成脏数据以及其大小;
used->实例空间被使用的大小;
flushes->每秒执行fsync数据写入的次数;
vsize->虚拟内存使用量,单位为G;
res->物理内存使用量,单位为MB;
qr|qw->当Mongodb接收到太多的命令而数据库被锁住无法执行完成,它会将命令加入队列。这一栏显示了总共、读、写3个队列的长度,都为0的话表示mongo毫无压力。高并发时,一般队列值会升高。
ar|aw->当前被激活的连接客户端数量,值越大越阻碍mongodb的性能。
netIn/netOut->网络带宽压力值,一般mongodb来说,网络不会成为瓶颈。
conn->当前连接数;
监控输出日志:
$sudo ./mongostat –n 10 >/mongodb/logs/stat_log.txt
上面即为将10行监听的结果输出到stat_log.txt文件中,方便查询分析。
输出结果显示:
如果实际中,服务器比较繁忙时,我们可以使用db.currentOp()快速获取当前执行的核心操作,具体如下所示:
如上图,inprog[]非空时,一般代表该台服务器有一定负载,这时我们可以查看一些耗时或是无用的操作,通过其opid停止掉它,具体如下:
> db.killOp(5098)
{ "info" :"attempting to kill op", "ok" : 1 }
另外,10gen公司发布一个web版本MongoDB监控服务工具,我们可以注册并使用其来更清晰化的监控信息,其工作原理及流程如下:
• 在MMS服务器上配置你的MongoDB信息(Host,Port,User,Passwd等)
• 在一台能够访问你MongoDB服务的内网机器上运行其提供的Agent脚本
• Agent脚本从MMS服务器获取到你配置的MongoDB信息
• Agent脚本连接到相应的MongoDB获取必要的监控数据
• Agent脚本将监控数据上传到MMS的服务器
• 登录MMS网站查看整理过后的监控数据图表了
具体操作这里不说明,有需要的伙伴可以直接去10gen官网注册并配置好自己的MongoDB服务就可以查看了,接下来我们来看下另一个监控工具mongotop的特点和它的使用。
2、mongotop
mongotop也是MongoDB的一内置工具,它的作用与mongostat类似,不够其注重监控的是实例的读写以及集合的统计数,偏向于整体结果显示,具体如下使用:
$sudo ./mongotop 5
上面的5代表间隔5秒的时长返回监控的结果输出,当然也可以设置,默认按每秒返回显示。
结果显示:
参数说明:
ns->数据库命名空间、名称和集合;
total->当前命名空间工作的时间总额;
read->当前命名空间的读取数据的时间速度;
write->当前命名空间的写入数据的时间额度
好了,Mongodb基础部分(二)就介绍到这里,由于作者水平有限,如有问题请在评论发言或是QQ群讨论,谢谢。
技术讨论群:
276592700(新)