mongodbmapreduce(mongodbMapReduce的三个过程)
本篇文章给大家谈谈mongodbmapreduce,以及mongodbMapReduce的三个过程对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
- 1、谈谈redis,memcache,mongodb的区别和具体应用场景
- 2、谁能说说mangodb 和 hbase的区别
- 3、在MongoDB 中实现模拟 join 查询有哪些方案,各有什么优缺点
- 4、redis和mongodb哪个简单
- 5、云上MongoDB常见索引问题及最优索引规则大全
- 6、如何实现mongodb中的sum汇总操作?
谈谈redis,memcache,mongodb的区别和具体应用场景
从以下几个维度,对 redis、memcache、mongoDB 做了对比。
1、性能
都比较高,性能对我们来说应该都不是瓶颈。
总体来讲,TPS 方面 redis 和 memcache 差不多,要大于 mongodb。
2、操作的便利性
memcache 数据结构单一。(key-value)
redis 丰富一些,数据操作方面,redis 更好一些,较少的网络 IO 次数,同时还提供 list,set,
hash 等橘慧数据结构的存储。
mongodb 支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富。
3、内存空间的大小和数据量的大小
redis 在 2.0 版本后增加了自己的 VM 特性,突破物理内存的限制;可以对 key value 设置过
期时间(类似 memcache)
memcache 可以修改最大可用内存,采用 LRU 算法。Memcached 代理软件 magent,比如建立
10 台 4G 的 Memcache 集群,就相当于有了 40G。 magent -s 10.1.2.1 -s 10.1.2.2:11211 -b
10.1.2.3:14000 mongoDB 适合大数据量的存储,依赖操作系统 VM 做内存管理,吃内存也比较厉害,服务
不要和别的服务在一起。
4、可用性(单点问题)
对于单点问题,
redis,依赖客户端来实现分布式读写;主从复制时,每次从节点重新连接主节点都要依赖整
个快照,无增量复制,因性能和效率问题,
所以单点问题比较复杂;不支持自动 sharding,需要依赖程序设定一致 hash 机制。
一种替代方案是,不用 redis 本身的复制机制,采用自己做培伍和主动复制(多份存储),或者改成
增量复制的方式(需要自己实现),一致性问题和性能的权衡
Memcache 本身没有数据冗余机制,也没必要;对于故障预防,采用依赖成熟的 hash 或者环
状的算法,解决单点故障引起的抖动问题。
mongoDB 支持 master-slave,replicaset(内部采用 paxos 选举算法,自动故障恢复),auto sharding 机制,对客户端屏蔽了故障转移和切分机制。
5、可靠性(持久化)
对于数据持久化和数据恢复,
redis 支持(快照、AOF):依赖快照进行持久化,aof 增强了可靠性的同时,对性能有所影
响
memcache 不支持,通常用在做缓存,提升性能;
MongoDB 从 1.8 版本开始采用 binlog 方式支持持久化的可靠性
6、数据一致性(事务支持)
Memcache 在并发场景下,用 cas 保证一致性redis 事务支持比较弱,只能保证事务中的每个操作连续执行
mongoDB 不支持事务
7、数据分析
mongoDB 内置了数据分析的功能(mapreduce),其他不支持
8、应用场景
redis:数据量较小的更性能操作和运算上
memcache:用于在动态系统中减少数据库负载,提升性能;做缓存,提高性能(适合读多写
少,对于数据量比较大,可以采用 sharding)
MongoDB:主要解决海量数据的访问效率问题。
表格比较:
memcache redis 类型 内存数据库 内存数据库
数据类型 在定义 value 时就要固定数据类型 不需要
有字符串,链表,集 合和有序集合
虚拟内存 不支持 支持
过期策略 支持 支持
分布式 magent master-slave,一主一从或一主多从
存储数据安全 不支持 使用 save 存储到 dump.rdb 中
灾难恢复 不支持 append only file(aof)用于数据恢复
性能
1、类型——memcache 和 redis 都是将数据存放在内存,所以是内存数据库。当然,memcache 也可用于缓存其他东西,例如图片等等。
2、 数据类型——Memcache 在添加数据时配盯就要指定数据的字节长度,而 redis 不需要。
3、 虚拟内存——当物理内存用完时,可以将一些很久没用到的 value 交换到磁盘。
4、 过期策略——memcache 在 set 时就指定,例如 set key1 0 0 8,即永不过期。Redis 可以通
过例如 expire 设定,例如 expire name 10。
5、 分布式——设定 memcache 集群,利用 magent 做一主多从;redis 可以做一主多从。都可
以一主一从。
6、 存储数据安全——memcache 断电就断了,数据没了;redis 可以定期 save 到磁盘。
7、 灾难恢复——memcache 同上,redis 丢了后可以通过 aof 恢复。
Memecache 端口 11211
yum -y install memcached
yum -y install php-pecl-memcache
/etc/init.d/memcached start memcached -d -p 11211 -u memcached -m 64 -c 1024 -P /var/run/memcached/memcached.pid
-d 启动一个守护进程
-p 端口
-m 分配的内存是 M
-c 最大运行并发数-P memcache 的 pid
//0 压缩(是否 MEMCACHE_COMPRESSED) 30 秒失效时间
//delete 5 是 timeout ?php
$memcache = new Memcache; $memcache - connect('127.0.0.1', 11211); $memcache - set('name','yang',0,30);
if(!$memcache-add('name','susan',0, 30)) {
//echo 'susan is exist'; }$memcache - replace('name', 'lion', 0, 300); echo $memcache - get('name');
//$memcache - delete('name', 5);
printf "stats\r\n" | nc 127.0.0.1 11211
telnet localhost 11211 stats quit 退出
Redis 的配置文件 端口 6379
/etc/redis.conf 启动 Redis
redis-server /etc/redis.conf 插入一个值
redis-cli set test "phper.yang" 获取键值
redis-cli get test 关闭 Redis
redis-cli shutdown 关闭所有
redis-cli -p 6379 shutdown ?php
$redis=new
Redis(); $redis-connect('127.0.0.1',6379); $redis-set('test',
'Hello World'); echo $redis-get('test'); Mongodb
apt-get install mongo mongo 可以进入 shell 命令行
pecl install mongo Mongodb 类似 phpmyadmin 操作平台 RockMongo
谁能说说mangodb 和 hbase的区别
1.Mongodb bson文档型数据库,整个亩亩数据都存在磁盘中,hbase是列式数据库,集群部署时每个familycolumn保存在单独的hdfs文件中。
2.Mongodb 主键是“_id”,主键上面可以不建索引,记录插入的顺序和存放的顺凳贺序一样,hbase的主键就是row key,可以是任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),在hbase内部,row key保存为字节数组。存储时,数据按照Row key的字典序(byte order)排序存储。设计key时,要充分排序存储这个特性,将经常一起读取的行存储放到一起。
字典序对int排序的结果是1,10,100,11,12,13,14,15,16,17,18,19,2,20,21,…,9,91,92,93,94,95,96,97,98,99。要保持整形的自然序,行键必须用0作左填充。
3.Mongodb支持二级索引,而hbase本身不支持二级索引
4.Mongodb支持集合查找,正则查找,范围查找,支持skip和limit等等,是最像mysql的nosql数据库,而hbase只支持三种查找:通过单个row key访问,通过row key的range,全表扫描
5.mongodb的update是update-in-place,也就是原地更新,除非原地容纳不下更新后的数据记录。而hbase的修改和添加都是同一个命令:put,如果put传入的row key已经存在就更新原记录,实际上hbase内部也不是更新,它只是将这一份数据已不同的版本保存下来而已,hbase默认的保存版本的历史数量是3。
6.mongodb的delete会将该行的数据标示为已删除,因为mongodb在删除记录时并不是真把记录从内存或文件中remove,而是将该删除记录数据置枣耐派空(写0或特殊数字加以标识)同时将该记录所在地址放到一个list列表“释放列表”中,这样做的好就是就是如果有用户要执行插入记录操作时,mongodb会首先从该“释放列表”中获取size合适的“已删除记录”地址返回,这种方法会提升性能(避免了malloc内存操作),同时mongodb也使用了bucket size数组来定义多个大小size不同的列表,用于将要删除的记录根据其size大小放到合适的“释放列表”中。Hbase的delete是先新建一个tombstonemarkers,然后读的时候会和tombstonemarkers做merge,在 发生major compaction时delete的数据记录才会真真删除。
7.mongodb和hbase都支持mapreduce,不过mongodb的mapreduce支持不够强大,如果没有使用mongodb分片,mapreduce实际上不是并行执行的
8.mongodb支持shard分片,hbase根据row key自动负载均衡,这里shard key和row key的选取尽量用非递增的字段,尽量用分布均衡的字段,因为分片都是根据范围来选择对应的存取server的,如果用递增字段很容易热点server的产生,由于是根据key的范围来自动分片的,如果key分布不均衡就会导致有些key根本就没法切分,从而产生负载不均衡。
9.mongodb的读效率比写高,hbase默认适合写多读少的情况,可以通过hfile.block.cache.size配置,该配置storefile的读缓存占用Heap的大小百分比,0.2表示20%。该值直接影响数据读的性能。如果写比读少很多,开到0.4-0.5也没问题。如果读写较均衡,0.3左右。如果写比读多,果断默认0.2吧。设置这个值的时候,你同时要参考hbase.regionserver.global.memstore.upperLimit,该值是memstore占heap的最大百分比,两个参数一个影响读,一个影响写。如果两值加起来超过80-90%,会有OOM的风险,谨慎设置。
10.hbase采用的LSM思想(Log-Structured Merge-Tree),就是将对数据的更改hold在内存中,达到指定的threadhold后将该批更改merge后批量写入到磁盘,这样将单个写变成了批量写,大大提高了写入速度,不过这样的话读的时候就费劲了,需要merge disk上的数据和memory中的修改数据,这显然降低了读的性能。mongodb采用的是mapfile+Journal思想,如果记录不在内存,先加载到内存,然后在内存中更改后记录日志,然后隔一段时间批量的写入data文件,这样对内存的要求较高,至少需要容纳下热点数据和索引。
在MongoDB 中实现模拟 join 查询有哪些方案,各有什么优缺点
方案一:将需要join的一部分字段作为embed嵌入宿主document
优点是一次查询搞定,性能好;缺点是数据冗余,并且嵌入的数据很难随着原数据同步修改,可能会造成数据不一致问题。
方案二:通过_id或DBRef进行link
优点是不会有数据冗余或数据不一致问题,缺点是需要多次查询才能获得所绝世需要的数据,开销大,在宿主document较多时尤其明显。
方案三:通过mongodb的mapreduce进行查询
优点是没有数据冗余或数据不一致问题,并且不需多次查询。缺并庆肢点是mongodb的mapreduce基于javascript引擎(目前是差唯spider monkey),单线程运行,所以效率略差,不适合实时查询。
redis和mongodb哪个简单
redis、memcahce 比较相似,但与 mongodb 完全不同,几乎没有可比性。
总的来说 redis/memcache 是基于内存的,讲究的是性能,多用作缓存层,比如说存放session。而 mongodb 是面向文档的,存储的是类似JSON的非结构化数据,查询起来非常方便,开发效率高,比较类似传统SQL关系型数据库。
从以下几个维度,对redis、memcache、mongoDB 做了对比:
体积
Redis是一个基于内存的键值数据库,它由C语言实现的,以单线程异步的方式工作,与Nginx/ NodeJS工作原理近似。所以文件非常小。编绎出来的主文件还不到 2Mb,在 Linux 服务器上初始只需要占用1Mb左右的内存。
Mongodb安装包则要大的多,跟mySQL差不多,都是百兆级的。
性能
都比较高,性能对拿态我们来说应该都不是瓶颈
总体来讲,TPS方面redis和memcache差不多,要大于mongodb
操作的便利性
memcache数据结构单一
redis丰富一些,数据操作方面,redis更好一些,较少的网络IO次数
mongodb支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富
推荐学习《python教程》
内存空间的大小和数据量的大小
redis在2.0版本后增加了自己的VM特性,突破物理内存的限制;可以对key value设置过期时间(类似memcache)
memcache可以修改最大可用内存,采用LRU算法
mongoDB适合大数据量的存储,依赖操作系统VM做内存管理,吃内存也比较厉害,服务不要和别的服务在一起
可用性(单点问题)
对于单点问题,
redis,依赖客户端拆蚂来实现分布式读写;主从复制时,每次从节点重新连接主节点都要依赖整个快照,无增量复制,因性能和效率问题,
所以单点问题比较复杂;不支持自动sharding,需要依赖程序设定一致hash 机制。
一种替代方案是,不用redis本身的复制机制,采用自己做主动复制(多份存储),或者改成增量复制的方式(需要自己实现),一致性问题和性能的权衡
Memcache本身没有数据冗余机制,也没必要;对于故障预防,采用依赖成熟的hash或者环状的算法,解决单点故障引起的抖动问题。
mongoDB支持master-slave,replicaset(内部采用paxos选举算法,自动故障恢复),auto sharding机制,对客户端屏蔽了故障转移和切分机制。
可靠性(持久化)
对于数据持久化和数据恢复,
redis支持(快照、AOF):依赖快照进行持久化,aof增强了可靠性的同时,对性能有所影响
memcache不支持,通常用在做缓存,提升性能;
MongoDB从1.8版本开始采用binlog方式支持持久化的可靠性,备份还原方法
7.数据一致性(事务支持)
Memcache 在并发场景下,用cas保证一致性
redis事务支持比较弱,只能保证事务中的每个操作连续执行
mongoDB不支持事务
8.数据分析
mongoDB内置了数据分析的功能(mapreduce),其他不支持
9.应旅敏埋用场景
redis:数据量较小的更性能操作和运算上
memcache:用于在动态系统中减少数据库负载,提升性能;做缓存,提高性能(适合读多写少,对于数据量比较大,可以采用sharding)
MongoDB:主要解决海量数据的访问效率问题。
云上MongoDB常见索引问题及最优索引规则大全
本文干货较多,建议收藏学习巧如。先将文章结构速览奉上:
一、背景
二、MongoDB执行计划
2.1 queryPlanner信息
2.2 executionStats信息
2.3 allPlansExecution信息
三、云上用户建索引常见问题及优化方法
3.1 等值类查询常见问题及优化方法
3.1.1 同一类查询创建多个索引问题
3.1.2 多字段等值查询组合索引顺序非最优
3.1.3 最左原则包含关系引起的重复索引
3.1.4 唯一字段和其他字段组合引起的无用重复索引
3.2 非等值类查询常见问题及优化方法
3.2.1 非等值组合查询索引不合理创建
3.2.2 等值+非等值组合查询索引字段顺序不合理
3.2.3 不同类型非等值查询优先级问题
3.3 OR类查询常见问题及优化方法
3.3.1 普通OR类查询优化方法
3.3.2 复杂OR类查询优化方法
3.4 SORT类排序查询常见问题及优化方法
3.4.1 单字段正反序排序查询引起的重复索引
3.4.2 多字段排序查询正反序问题引起索引无效
3.4.3 等值查询+多字段排序组合查询
3.4.4 等值查询+非等值查询+SORT排序查询
3.4.5 OR+SORT组合排序查询
3.5 无用索引优化方法
四、MongoDB不同类型查询最优索引总结
腾讯云MongoDB当前已服务于 游戏 、电商、社交、教育、新闻资讯、金融、物联网、软件服务、 汽车 出行、音视频等多个行业。
腾讯MongoDB团队在配合用户分析问题过程中,发现 云上用户存在如下索引共性问题 ,主要集中在如下方面:
本文 重点分析总结腾讯云上用户索引创建不合理相关的问题 ,通过本文可以学习到MongoDB的以下知识点:
本文总结的 《最优索引规则创建大全》 不仅仅适用于MongoDB,很多规则 同样适用于MySQL等关系型数据库 。
判断索引选择及不同索引执行家伙信息可以通过explain操作获取, MongoDB通过explain来获取尺信SQL执行过程信息 ,当前持续explain的请求命令包含以下几种:
aggregate, count, distinct, find, findAndModify, delete, mapReduce, and update。
详见explain官网链接:
explain可以携带以下几个参数信息,各参数信息功能如下:
2.1 queryPlanner信息
获取MongoDB查询优化器选择的最优索引和拒绝掉的非最优索引,并给出各个候选索引的执行阶段信息,queryPlanner输出信息如下:
queryPlanner输出主要包括如下信息:
parsedQuery信息
内核对查询条件进行序列化,生成一棵expression tree信息,便于候选索引查询匹配。
winningPlan信息
rejectedPlans信息
输出信息和winningPlan类似,记录这些拒绝掉索引的执行stage信息。
2.2 executionStats信息
explain的executionStats参数除了提孝困启供上面的queryPlanner信息外,还提供了最优索引的执行过程信息,如下:
上面是通过executionStats获取执行过程的详细信息,其中字段信息较多,平时分析索引问题最常用的几个字段如下:
executionStats输出字段较多,其他字段将在后续《MongoDB内核index索引模块实现原理》中进行进一步说明。
在实际分析索引问题是否最优的时候,主要查看以下三个统计项:
executionStats.totalKeysExamined
executionStats.totalDocsExamined
executionStats .nReturned
如果存在以下情况则说明索引存在问题,可能索引不是最优的:
1. executionStats.totalKeysExamine远大于executionStats .nReturned
2. executionStats. totalDocsExamined远大于executionStats .nReturned
2.3 allPlansExecution信息
allPlansExecution参数对应输出信息和executionStats输出信息类似,只是多了所有候选索引(包括reject拒绝的非最优索引)的执行过程,这里不再详述。
2.4 总结
从上面的几个explain执行计划参数输出信息可以看出,各个参数的功能各不相同,总结如下:
queryPlanner
输出索引的候选索引,包括最优索引及其执行stage过程(winningPlan)+其他非最优候选索引及其执行stage过程。
注意: queryPlanner没有真正在表中执行整个SQL,只做了查询优化器获取候选索引过程,因此可以很快返回。
executionStats
相比queryPlanner参数,executionStats会记录查询优化器根据所选最优索引执行SQL的整个过程信息,会真正执行整个SQL。
allPlansExecution
和executionStats类似,只是多了所有候选索引的执行过程。
在和用户一起优化腾讯云上MongoDB集群索引过程中,以及和头部用户的交流中发现很多用户对如何创建最优索引有较为严重的错误认识,并且很多是绝大部分用户的共性问题,因此在本文中将这些问题汇总如下:
3.1 等值类查询常见问题及优化方法
如下三个查询:
用户创建了如下3个索引:
{a:1, b:1, c:1}
{b:1, a:1, c:1}
{c:1, a:1, b:1}
实际上这3个查询属于同一类查询,只是查询字段顺序不一样,因此只需创建任一个索引即可满足要求。验证过程如下:
从上面的expalin输出可以看出,3个查询都走向了同一个索引。
例如test表有多条数据,每条数据有3个字段,分别为a、b、c。其中a字段有10种取值,b字段有100种取值,c字段有1000种取值,称为各个字段值的 “区分度” 。
用户查询条件为db.test.find({"a":"xxx", "b":"xxx", "c":"xxx"}),创建的索引为{a:1, b:1, c:1}。如果只是针对这个查询,该查询可以创建a,b,c三字段的任意组合,并且其SQL执行代价一样,通过hint强制走不通索引,验证过程如下:
从上面的执行计划可以看出,多字段等值查询各个字段的组合顺序对应执行计划代价一样。绝大部分用户在创建索引的时候,都是直接按照查询字段索引组合对应字段。
但是,单就这一个查询,这里有个不成文的建议,把区分度更高的字段放在组合索引左边,区分度低的字段放到右边。这样做有个好处,数据库组合索引遵从最左原则,就是当其他查询里面带有区分度最高的字段时,就可以快速排除掉更多不满足条件的数据。
例如用户有如下两个查询:
用户创建了如下两个索引:
{b:1, c:1}
{a:1,b:1,c:1}
这两个查询中,查询2中包含有查询1中的字段,因此可以用一个索引来满足这两个查询要求,按照最左原则,查询1字段放左边即可,该索引可以优化为:b,c字段索引+a字段索引,b,c字段顺序可以根据区分排序,加上c字段区分度比b高,则这两个查询可以合并为一个{c:1, b:1, a:1}。两个查询可以走同一个索引验证过程如下:
从上面输出可以看出,这两个查询都走了同一个索引。
例如用户有以下两个查询:
用户为这两个查询创建了两个索引,{a:1, b:1}和{a:1, c:1},但是a字段取值是唯一的,因此这两个查询中a以外的字段无用,一个{a:1}索引即可满足要求。
3.2 非 等值类查询常见索引错误创建方法及如何创建最优索引
假设用户有如下查询:
a,c两个字段都是非等值查询,很多用户直接添加了{a:1, c:1}索引,实际上多个字段的非等值查询,只有最左边的字段才能走索引,例如这里只会走a字段索引,验证过程如下:
从上面执行计划可以看出,索引数据扫描了10行(也就是a字段满足a:{$gte:1}条件的数据多少),但是实际上只返回了4条满足{a:{$gte:1}, c:{$lte:1}}条件的数据,可以看出c字段无法做索引。
同理,当查询中包含多个字段的范围查询的适合,除了最左边第一个字段可以走索引,其他字段都无法走索引。因此,上面例子中的查询候选索引为{a:1}或者{b:1}中任何一个就可以了,组合索引中字段太多会占用更多存储成本、同时占用更多IO资源引起写放大。
例如下面查询:
如上查询,d字段为非等值查询,e字段为等值查询,很多用户遇到该类查询直接创建了{d:1, e:1}索引,由于d字段为非等值查询,因此e字段无法走索引,验证过程如下:
从上面验证过程可以看出,等值类和非等值类组合查询对应组合索引,最优索引应该优先把等值查询放到左边,上面查询对应最优索引{e:1, d:1}
前面用到的非等值查询操作符只提到了比较类操作符,实际上非等值查询还有其他操作符。常用非等值查询包括:$gt、$gte、$lt、$lte、$in、$nin、$ne、$exists、$type等,这些非等值查询在绝大部分情况下存在如下优先级:
从上到下优先级更高,例如下面的查询:
如上,该查询等值部分查询最优索引{a:1, b:1}(假设a区分度比b高);非等值部分,因为$in操作符优先级最高,排他性更好,加上多个字段非等值查询只会有一个字段走索引,因此非等值部分最优索引为{g:1}。
最终该查询最优索引为:”等值部分最优索引”与”非等值部分最优索引”拼接,也就是{a:1,b:1, g:1}
3.3 OR类查询常见索引错误创建方法及如何创建最优索引
例如下面的OR查询:
该查询很多用户直接创建了{b:1, d:1, c:1, a:1},用户创建该索引后,发现用户还是全表扫描。
OR类查询需要给数组中每个查询添加索引,例如上面or数组中实际包含{ b: 0, d:0 }和 {"c":1, "a":{$gte:4}}查询,需要创建两个查询的最优索引,也就是{b:1, d:1}和{c:1, a:1},执行计划验证过程如下(该测试表总共10条数据):
从上面执行计划可以看出,如果该OR类查询走{b:1, d:1, c:1, a:1}索引,则实际上做了全表扫描。如果同时创建{b:1, d:1}、{c:1, a:1}索引,则直接走两个索引,其执行key和doc扫描行数远远小于全表扫描。
这里在提升一下OR查询难度,例如下面的查询:
上面的查询可以转换为如下两个查询:
如上图,查询1拆分后的两个查询2和查询3组成or关系,因此对应最优索引需要创建两个,分表是:{f:1, g:1, b:1, d:1} 和 {f:1, g:1, b:1, d:1}。对应执行计划如下:
同理,不管怎么增加难度,OR查询最终可转换为多个等值、非等值或者等值与非等值组合类查询,通过如上变换最终可以起到举一反三的作用。
说明:这个例子中可能在一些特殊数据分布场景,最优索引也可能是{f:1, g:1}或者{f:1, g:1, b:1, d:-1}或者{ f:1, g:1, c:1, a:1},这里我们只考虑大部分通用场景。
3.4 SORT类排序查询常见索引错误创建方法及如何创建最优索引
例如用户有以下两个查询:
这两个查询都不带条件,排序方式不一样,因此很多创建了两个索引{a:1}和{a:-1},实际上这两个索引中的任何一个都可以满足两种查询要求,验证过程如下:
假设有如下查询:
其中a字段为正序,b字段为反序排序,很多用户直接创建{a:1, b:1}索引,这时候b字段内容就存在内存排序情况。多字段排序索引,如果没有携带查询条件,则最优索引即为排序字段对应索引,这里切记保持每个字段得正反序和sort完全一致,否则可能存在部分字段内存排序的情况,执行计划验证过程如下:
例如如下查询:
该类查询很多人直接创建{a:1, b:1, c:1, d:1},结果造成内存排序。这种组合查询最优索引=“多字段等值查询最优索引_多字段排序类组合最优索引”,例如该查询:
{ "a" : 3, "b" : 1}等值查询假设a区分度比b高,则对应最优索引为:{a:1, b:1}
{ c:-1, d:1}排序类查询最优索引保持正反序一致,也就是:{ c:-1, d:1}
因此整个查询就是这两个查询对应最优索引拼接,也就是{a:1, b:1, c:-1, d:1},对应执行计划过程验证如下:
假设有下面的查询:
腾讯云很多用户看到该查询直接创建{a:1, b:1, c:1, d:-1, e:1}索引,发现存在内存排序。等值+非等值+sort排序组合查询,由于非等值查询右边的字段不能走索引,因此如果把d, e放到c的右边,则d,e字段索引无效。
等值+非等值+sort排序最优索引组合字段顺序为:等值_sort排序_非等值,因此上面查询最优索引为:{a:1, b:1, d:-1, e:1, c:1}。执行计划验证过程如下:
例如如下查询:
上面组合很多人直接创建{b:1, d:1, c:1, a:1, e:1},该索引创建后还是会扫表和内存排序,实际上OR+SORT组合查询可以转换为下面两个查询:
所以这个复杂查询就可以拆分为等值组合查询+sort排序查询,拆分为上面的两个查询,这样我们只需要同时创建查询2和查询3对应最优索引即可。该查询最终拆分后对应最优索引需要添加如下两个:
{b:1, d:1, e:-1}和{c:1, a:1, e:-1}
非最优索引和最优索引执行计划验证过程如下:
OR+SORT类查询,最终可以《参考前面的OR类查询常见索引错误创建方法》把OR查询转换为多个等值、非等值或者等值与非等值组合查询,然后与sort排序对应索引字段拼接。例如下面查询:
拆分后的两个查询组成or关系,如下:
如上,查询1 = or: [查询2, 查询3],因此只需要创建查询2和查询3两个最优索引即可满足查询1要求,查询2和查询3最优索引可以参考前面《or类查询常见索引错误创建方法》,该查询最终需要创建如下两个索引:
{f:1, g:1, b:1, d:1, e:-1}和{ f:1, g:1, c:1, a:1, e:-1}
说明:这个例子中可能在一些特殊数据分布场景,最优索引也可能是{f:1, g:1}或者{f:1, g:1, b:1, d:1, e:-1}或者{ f:1, g:1, c:1, a:1, e:-1},这里我们只考虑通用场景。
3.5 避免创建太多无用索引及无用索引分析方法
在腾讯云上,我们还发现另外一个问题,很多实例存在大量无用索引,无用索引会引起以下问题:
存储成本增加
没增加一个索引,MongoDB内核就会创建一个index索引文件,记录该表的索引数据,造成存储成本增加。
影响写性能
用户没写入一条数据,就会在对应索引生成一条索引KV,实现索引与数据的一一对应,索引KV数据写入Index索引文件过程加剧写入负载。
影响读性能
MongoDB内核查询优化器原理是通过候选索引快速定位到满足条件的数据,然后采样评分。如果满足条件的候选索引越多,整个评分过程就会越长,增加内核选择最优索引的流程。
下面以一个真实线上实例为例,说明如何找出无用索引:
MongoDB默认提供有索引统计命令来获取各个索引命中的次数,该命令如下:
该聚合输出中的几个核心指标信息如下表:
上表中的ops代表命中次数,如果命中次数为0或者很小,说明该索引很少被选为最优索引使用,因此可以认为是无用索引,可以考虑删除。
说明:
本文总结的《最优索引规则大全》中的规则适用于绝大部分查询场景,但是一些特殊数据分布场景可能会有一定偏差,请根据实际数据分布进行查询计划分析。
DBbrain for MongoDB
最后,本文中所介绍的优化原理即将集成到腾讯云DBbrain for MongoDB的智能索引推荐(规则+代价计算)功能中,届时可帮助用户一键优化索引,无需亲自反复推敲验证,欢迎体验。
腾讯云MongoDB当前服务于 游戏 、电商、社交、教育、新闻资讯、金融、物联网、软件服务等多个行业;MongoDB团队(简称CMongo)致力于对开源MongoDB内核进行深度研究及持续性优化(如百万库表、物理备份、免密、审计等),为用户提供高性能、低成本、高可用性的安全数据库存储服务。后续持续分享MongoDB在腾讯内部及外部的典型应用场景、踩坑案例、性能优化、内核模块化分析。
﹀
﹀
﹀
叮咚买菜自建MangoDB上腾讯云实践
[img]如何实现mongodb中的sum汇总操作?
首先在本亮则伍地机器上安装并敬或设置MongoDB服务。
从Mongo网站上下载MongoDB,解压到本地目录,比如C:Mongo
在上一个文件夹内创建数据目录。比如:C:\Mongo\Data
如果数据文件存放在其他地方,那么在用mongod.exe命令启动MongoDB时,需要在命令行加参数—-dbpath
启动服务
MongoDB提供了两种方式:mongod.exe以后台进程启动;mongo.exe启动命令行界面,可做管理操作。这两个可执行文件都位于Mongo\bin目录下;
进入Mongo安装目录的bin目录下,比如:C: cd Mongo\bin
有两种启动方式,如下:
mongod.exe –dbpath C:\Mongo\data
或者
mongod.exe –config mongodb.config
mongodb.config是Mongo\bin目录下的配置文件,需要在此配置文件中指定数据目录(比如,dbpath= C:\Mongo\Data)的位置。
连接到MongoDB,到这一步,mongo后台服务已经启动,可以通过查看。 MongoDB启动运行后,我们接下来看它的聚合函数。
实现聚合函数
在关系数据库中,我们可以在数值型字段上执行包含预定义聚合函数的SQL语句,比如,SUM()、COUNT()、MAX()和MIN()。但是在MongoDB中,需要通过MapReduce功能来实现聚合以及批处理,它跟SQL里用来实现聚合的GROUP BY从句比较类似。下一节将描述关系数据库中SQL方式实现的聚合和相应的通过MongoDB提供的MapReduce实现的聚合。
为了讨论这个主题,我们考虑如下所盯绝示的Sales表,它以MongoDB中的反范式形式呈现。
Sales表
#
列名
数据类型
1
OrderId
INTEGER
2
OrderDate
STRING
3
Quantity
INTEGER
4
SalesAmt
DOUBLE
5
Profit
DOUBLE
6
CustomerName
STRING
7
City
STRING
8
State
STRING
9
ZipCode
STRING
10
Region
STRING
11
ProductId
INTEGER
12
ProductCategory
STRING
13
ProductSubCategory
STRING
14
ProductName
STRING
15
ShipDate
STRING
基于SQL和MapReduce的实现
我们提供了一个查询的样例集,这些查询使用聚合函数、过滤条件和分组从句,及其等效的MapReduce实现,即MongoDB实现SQL中GROUP BY的等效方式。在MongoDB存储的文档上执行聚合操作非常有用,这种方式的一个限制是聚合函数(比如,SUM、AVG、MIN、MAX)需要通过mapper和reducer函数来定制化实现。
MongoDB没有原生态的用户自定义函数(UDFs)支持。但是它允许使用db.system.js.save命令来创建并保存JavaScript函数,JavaScript函数可以在MapReduce中复用。下表是一些常用的聚合函数的实现。稍后,我们会讨论这些函数在MapReduce任务中的使用。
聚合函数
Javascript 函数
SUM
db.system.js.save( { _id : "Sum" ,
value : function(key,values)
{
var total = 0;
for(var i = 0; i values.length; i++)
total += values[i];
return total;
}});
AVERAGE
db.system.js.save( { _id : "Avg" ,
value : function(key,values)
{
var total = Sum(key,values);
var mean = total/values.length;
return mean;
}});
MAX
db.system.js.save( { _id : "Max" ,
value : function(key,values)
{
var maxValue=values[0];
for(var i=1;i
MIN
db.system.js.save( { _id : "Min" ,
value : function(key,values)
{
var minValue=values[0];
for(var i=1;i
VARIANCE
db.system.js.save( { _id : "Variance" ,
value : function(key,values)
{
var squared_Diff = 0;
var mean = Avg(key,values);
for(var i = 0; i values.length; i++)
{
var deviation = values[i] - mean;
squared_Diff += deviation * deviation;
}
var variance = squared_Diff/(values.length);
return variance;
}});
STD DEVIATION
db.system.js.save( { _id : "Standard_Deviation"
, value : function(key,values)
{
var variance = Variance(key,values);
return Math.sqrt(variance);
}});
SQL和MapReduce脚本在四种不同的用例场景中实现聚合函数的代码片段如下表所示。
1.各地区的平均订单量
下面的查询是用来获取不同地区的平均订单量。
SQL Query
MapReduce Functions
SELECT
db.sales.runCommand(
{
mapreduce : "sales" ,
City,
State,
Region,
map:function()
{ // emit function handles the group by
emit( {
// Key
city:this.City,
state:this.State,
region:this.Region},
// Values
this.Quantity);
},
AVG(Quantity)
reduce:function(key,values)
{
var result = Avg(key, values);
return result;
}
FROM sales
GROUP BY City, State, Region
// Group By is handled by the emit(keys, values)
line in the map() function above
out : { inline : 1 } });
2.产品的分类销售总额
下面的查询是用来获取产品的分类销售额,根据产品类别的层级分组。在下面例子中,不同的产品类别作为个体维度,它们也可以被称为更复杂的基于层次的维度。
SQL 查询
MapReduce 函数
SELECT
db.sales.runCommand(
{
mapreduce : "sales" ,
ProductCategory, ProductSubCategory, ProductName,
map:function()
{
emit(
// Key
{key0:this.ProductCategory,
key1:this.ProductSubCategory,
key2:this.ProductName},
// Values
this.SalesAmt);
},
SUM(SalesAmt)
reduce:function(key,values)
{
var result = Sum(key, values);
return result;
}
FROM sales
GROUP BY ProductCategory, ProductSubCategory, ProductName
// Group By is handled by the emit(keys, values)
line in the map() function above
out : { inline : 1 } });
3. 一种产品的最大利润
下面的查询是用来获取一个给定产品基于过滤条件的最大利润。
SQL查询
MapReduce 函数
SELECT
db.sales.runCommand(
{
mapreduce : "sales" ,
ProductId, ProductName,
map:function()
{
if(this.ProductId==1)
emit( {
key0:this.ProductId,
key1:this.ProductName},
this.Profit);
},
MAX(SalesAmt)
reduce:function(key,values)
{
var maxValue=Max(key,values);
return maxValue;
}
FROM sales
WHERE ProductId=’1’
// WHERE condition implementation is provided in
map() function
GROUP BY ProductId, ProductName
// Group By is handled by the emit(keys, values)
line in the map() function above
out : { inline : 1 } });
4. 总量、总销售额、平均利润
这个场景的需求是计算订单的总数、总销售额和平均利润,订单ID在1到10之间,发货时间在2011年的1月1日到12月31日之间。下面的查询是用来执行多个聚合,比如,在指定年份以及指定的不同区域和产品类别范围里订单的总数、总销售额和平均利润。
SQL 查询
MapReduce 函数
SELECT
db.sales.runCommand(
{ mapreduce : "sales" ,
Region,
ProductCategory,
ProductId,
map:function()
{
emit( {
// Keys
region:this.Region,
productCategory:this.ProductCategory,
productid:this.ProductId},
// Values
{quantSum:this.Quantity,
salesSum:this.SalesAmt,
avgProfit:this.Profit} );
}
Sum(Quantity),
Sum(Sales),
Avg(Profit)
reduce:function(key,values)
{
var result=
{quantSum:0,salesSum:0,avgProfit:0};
var count = 0;
values.forEach(function(value)
{
// Calculation of Sum(Quantity)
result.quantSum += values[i].quantSum;
// Calculation of Sum(Sales)
result.salesSum += values[i].salesSum;
result.avgProfit += values[i].avgProfit;
count++;
}
// Calculation of Avg(Profit)
result.avgProfit = result.avgProfit / count;
return result;
},
FROM Sales
WHERE
Orderid between 1 and 10 AND
Shipdate BETWEEN ‘01/01/2011’ and
‘12/31/2011’
query : {
"OrderId" : { "$gt" : 1 },
"OrderId" : { "$lt" : 10 },
"ShipDate" : { "$gt" : "01/01/2011" },
"ShipDate" : { "$lt" : "31/12/2011" },
},
GROUP BY
Region, ProductCategory, ProductId
// Group By is handled by the emit(keys, values)
line in the map() function above
LIMIT 3;
limit : 3,
out : { inline : 1 } });
既然我们已经看了在不同业务场景下的聚合函数的代码示例,接下来我们准备来测试这些函数。
测试聚合函数
MongoDB的MapReduce功能通过数据库命令来调用。Map和Reduce函数在前面章节里已经使用JavaScript实现。下面是执行MapReduce函数的语法。
db.runCommand(
{ mapreduce : collection,
map : mapfunction,
reduce : reducefunction
[, query : query filter object]
[, sort : sorts the input objects using this key. Useful for
optimization, like sorting by the emit key for fewer reduces]
[, limit : number of objects to return from collection]
[, out : see output options below]
[, keeptemp: true|false]
[, finalize : finalizefunction]
[, scope : object where fields go into javascript global scope ]
[, jsMode : true]
[, verbose : true]
}
)
Where the Output Options include:
{ replace : "collectionName" }
{ merge : "collectionName"
{ reduce : "collectionName" }
{ inline : 1}
关于mongodbmapreduce和mongodbMapReduce的三个过程的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。