Mongodb 笔记04 特殊索引和集合、聚合、应用程序设计
特殊索引和集合
1. 固定集合:固定集合需要事先创建好看,而且它的大小是固定的。当固定集合被占满时,如果再插入新文档,固定集合会自动将最老的文档从集合中删除。
2. 创建固定集合:db.createCollection("my_collection",{"capped":true,"size":10000}) 创建一个大小为10000字节的固定集合
除了大小,createCollection还能指定固定集合中文档的数量:db.createCollection("my_collection",{"capped":true,"size":10000,"max":10})
指定文档数量时,必须同时指定集合大小。固定集合的文档数量不能超过文档数量限制,固定集合的大小也不能超过大小限制。
3. 将某个常规集合转换为固定集合:db.runCommand({"convertToCapped":"test","size":10000}) 无法将固定集合转换为非固定集合。
4. 自然排序:自然排序返回结果集中文档的顺序就是文档在磁盘上的顺序。只有固定集合中的自然排序才有意义,对其他集合来说文档位置经常变化,自然排序意义不大。
5. 循环游标:一种特殊的游标,当循环游标的结果集被取光后,游标不会被关闭。当有新文档插入到集合时,循环游标会继续取到结果。由于普通集合并不维护文档的插入顺序,循环游标只能用在固定集合上。
6. 调用createCollection创建集合时指定autoIndexId选项为false,创建集合时就不会自动在"_id"上创建索引。实践中不建议这么用,但对于只有插入操作的集合来说,这确实可以带来速度上的稍许提升。
7. TTL索引:如果需要更加灵活的老化移出系统,可以使用TTL索引,这种索引允许为每一个文档设置一个超时时间。一个文档到达预设置的老化程度之后就会被删除。这种类型的索引对于缓存问题很有用。
db.foo.ensureIndex({"lastUPdated":1},{"expireAfterSecs":60*60*24}) // 过期时间24小时
MongoDB每分钟对TTL索引进行一次清理,所以不应该依赖以秒为单位的时间保证索引的存活状态。可以使用collMod命令修改expireAfterSecs的值:
db.runCommand({"collMod":"someapp.cache","expireAfterSecs":3600})
一个给定的集合上可以有多个TTL索引,但TTL不能是复合索引。
8. 全文本索引:暂不建议使用,性能影响太大。
9. 地理空间索引:最常用的是2dsphere索引(用于地球表面类型的地图)和2d索引(用于平面地图和时间连续的数据)
10. 使用GridFS存储文件:GridFS是MongoDB的一种存储机制,用来存储大型二进制文件。
优点:
a. 简化你的栈,可以使用GRIDFS来代替独立的文件存储工具。
b. 对文件存储做故障转义或者横向扩展更容易
c. 可以比较从容地解决其他一些文件系统可能遇到的问题。
d. 文件存储的集中度会比较高
缺点:
a. 性能低:从MongoDB中访问文件,不如直接从文件系统中访问文件速度快。
b. 如果要修改GridFS上的文档,只能先将已有的文档删除。
通常来说,如果你有一些不常改变但是经常需要连续访问的大文件,那么使用GridFS再合适不过。(性能呢?因为缓存到内存了?)
11. GridFS背后的理念:可以将大文件分割为多个比较大的块,将每个快作为独立的文档进行存储。有一个文档用于将这些块组织在一起并存储该文档的元信息。
12. 可以使用任何自定义的字段来保存必须的文件元信息。可能你希望在文件元信息中保存文件的下载次数,MIME类型或者用户评分。
聚合
如果你有数据存储在MongoDB中,你想做的可能就不仅仅是将数据提取出来那么简单;你可能希望对数据进行分析加以利用。本章介绍MongoDB提供的聚合工具
1. 聚合框架:使用聚合框架可以对集合中的文档进行变化和组合。基本上,可以用多个构架创建一个管道,用于对一连串的文档进行处理。这些构件包括筛选、投射、分组、排序、限制和跳过。
2. 管道操作符:每个操作符都会接受一连串的文档,对这些文档做一些类型转换,最后将转换后的文档作为结果传递给下一个操作(对于最后一个管道操作符,是将结果返回给客户端)。不同的
管道操作符可以按任意顺序组合在一起使用,而且可以被重复任意多次。
1). $match : $match用于对文档集合进行筛选,之后就可以在筛选得到的文档子集上做聚合。在实际使用中应该尽可能将"$match"放在管道的前面位置,这样有两个好处:
a. 可以快速将不需要的文档过滤掉,以减少管道的工作量
b. 如果在投射和分组之前执行"$match",查询可以使用索引
用法:{$match:{"state":"OR"}}
2). $project : 可以从文档中提取字段,可以重命名字段,还可以进行一些其他操作。
用法:db.articles.aggregate({"$project":{"author":1,"_id":0}}) 只返回author字段。
字段重命名:{"$project":{"userId":"$_id","_id":0}} $fieldname语法是为了在聚合框架中引用fieldname字段的值。重命名后不能使用原字段上的索引。
数学表达式:
a. $add : [expr1[,expr2....exprN] 这个操作符是接收一个或多个表达式作为参数,将这些表达式相加
b. $subtract : [expr1,expr2] 接收两个表达式,用第一个表达式减去第二个表达式作为结果
c. $multiply : [expr1[,expr2.....exprN] : 将参数相乘
d. $divide : [expr1,expr2] 第一个表达式除以第二个表达式的商作为结果
e. $mod [expr1,expr2] 第一个表达式除以第二个表达式的余数作为结果
日期表达式
$year ,$month,$week,$dayOfMonth,$dayOfWeek,$dayOfYear,$hour,$minute,$second
字符串表达式:
a. $substr : [expr,startOffset,numToReturn] : 截取字符串,从startOffset字节开始的numToReturn字节。注意是字节不是字符。
b. $concat : [expr1,expr2,....exprN] : 将给定的表达式(或者字符串)连接在一起作为返回结果
c. $toLower : expr 返回小写形式
d. $toUpper: expr 返回大写形式
逻辑运算符:
$cmp:[expr1,expr2] : 比较expr1和expr2。如果expr1等于expr2,返回0,;如果expr1小于expr2;返回负数;如果大于,返回正数
$strcasecmp:[string1,string2] : 比较字符串大小
$eq/$ne/$gt/$gte/$lt/$lte:[expr1,expr2]
几个布尔表达式:
$and:[expr1,expr2...exprN] 如果所有表达式都为true,则返回true,否则返回false
$or : [expr1,expr2...exprN] 有一个为true,则返回true
$not : expr 对表达式取反
两个控制语句:
$cond :[booleanExpr,trueExpr,falseExpr] : 如果booleanExpr为true,返回trueExpr,否则返回falseExpr
$ifNull : [expr,replacementExpr] : 如果expr为null,返回replacementExpr,否则返回expr
3). $group : $group 操作可以将文档依据特定字段的不同值进行分组。
4). $unwind : 拆分(unwind) 可以将数组的每一个值拆分成单独的文档。
5). $sort : 可以根据任何字段进行排序,与在普通查询中的语法相同。如果要对大量的文档进行排序,建议在管道的第一阶段进行排序,这样可以使用索引。
6). $limit : 接收一个数字n,返回集合中的前n个字段
7). $skip : 接收一个数字n,丢弃结果集中的前n个文档。
3. 使用管道:应该尽量在管道的开始阶段就将尽可能多的文档和字段过滤掉。管道如果不是直接从原先的集合中使用数据,那就无法再筛选和排序中使用索引。如果可能,聚合管道会尝试对操作进行排序,
以便能够有效的使用索引。如果MongoDB发现某个聚合操作占用了20%以上的内存,这个操作就会直接输出错误。
如果能够通过$match操作迅速减小结果集的大小,就可以使用管道进行实时聚合。
4. MapReduce : 非常强大,非常灵活。但速度慢,不应该用在实时的数据分析中。
5. 聚合命令:
1). count : db.foo.count()
2). distinct : db.runCommand({"distinct":"people","key":"age"})
3). group
应用程序设计
1. 范式化:将数据分散到多个不同的集合,不用集合之间可以相互引用数据。虽然很多文档可以引用某一块数据,但是这块数据只存储在一个集合。
反范式化:将每个文档所需的数据都嵌入在文档内部。每个文档都拥有自己的数据副本,而不是所有文档共同引用同一个数据副本。
范式化能够提高数据写入速度,反范式化能够提高数据读取速度。
2. 更适合内嵌:子文档较小,数据不会定期改变,最终数据一致性即可,文档数据小幅增加,数据通常需要执行二次查询才能获得,快速读取
更适合引用:子文档较大,数据经常变化,中间阶段的数据必须一致,文档数据大幅增加,数据通常不包含在结果中,快速写入
3. 优化数据操作:如果要优化应用程序,首先必须知道对读写性能进行评估以便能找到性能瓶颈。对读取操作的优化通常包括正确使用索引,以及尽可能将所需信息放在单个文档中返回,
对写入操作的优化通常包括减少索引数量以及尽可能提高更新效率。
4. 经常需要再写入效率更高的模式与读取效率更高的模式之间权衡,所以必须要知道哪种操作对你的应用程序更重要。这里的影响因素并不只是读取和写入的重要性,也包括读取和写入操作的频繁程度.
5. 数据优化方式:
1). 优化文档增长:更新数据时,需要明确更新是否会导致文件体积增大,以及增长程度。如果增长程序是可预知的,可以为文档预留足够的增长空间,这样可以避免文档移动,提高写入速度。
检测一下填充因子,如果它大约是1.2或者更大,可以考虑手动填充。如果要对文档手动填充,可以在填充文档时创建一个占用空间比较大的字段,文档创建成功之后删除这个字段。
插入时添加或者在upsert时,使用$setOnInsert创建这个字段。更新文档时,使用$unset移除。如果这个字段不存在,$unset操作什么也不做。
可以考虑将会增长的字段,放在最后面。
2). 删除旧数据,主要有三种方式:使用固定集合,使用TTL集合,使用定期删除集合。
6. 一致性管理:
服务器为每个数据库连接维护一个请求队列。客户端每次发来的新请求都会添加到队列末尾。入队之后,这个连接上的请求会一次得到处理。一个连接拥有一个一致的数据库视图,可以总是读取到这个
连接最新写入的数据。注意,每个队列只对应一个连接:如果打开两个shell,连接到相同的数据库,这时就存在两个不同的连接。如果在齐中一个shell中执行插入操作,紧接着在另一个shell中执行
查询操作,新插入的数据肯呢个不会出现在查询结果中。
7. 不适合使用MongoDB的场景:
1). MongoDB不支持事务
2). 无法在多个维度上对不同类型的数据库进行连接。
3). 你使用的工具不支持MongoDB
Mongodb 笔记04 特殊索引和集合、聚合、应用程序设计的更多相关文章
- 6.MongoDB系列之特殊索引和集合类型
1. 地理空间索引及全文搜索 与Elasitcsearch一样,MongoDB同样支持地理空间索引及全文搜索,由于选型常用ES而非MongoDB此处略过 2. TTL索引 首先先了解下固定集合,其类似 ...
- JS自学笔记04
JS自学笔记04 arguments[索引] 实参的值 1.对象 1)创建对象 ①调用系统的构造函数创建对象 var obj=new Object(); //添加属性.对象.名字=值; obj.nam ...
- MongoDB学习笔记-04 索引
索引是用来加速查询的.有了索引之后,数据库不必进行全表扫描,只需先在索引中查找,再根据找到的索引查找数据.MongoDB的索引几乎和传统关系型数据库一样. 创建索引 创建索引是在相应的集合中使用ens ...
- Mongodb Manual阅读笔记:CH7 索引
7索引 Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作Mongodb Manual阅读笔记:CH3 数据模型(Data Models)Mongodb Manual阅读笔记 ...
- MongoDB学习笔记四:索引
索引就是用来加速查询的.创建数据库索引就像确定如何组织书的索引一样.但是你的优势是知道今后做何种查询,以及哪些内容需要快速查找.比如:所有的查询都包括"date"键,那么很可能(至 ...
- MongoDB学习笔记04
创建索引使用ensureIndex方法,对于同一个集合,同样的索引只需要创建一次,反复创建是徒劳的. 对某个键的索引会加速对该键的查询,然而,对于其它查询可能没有帮助,即便是查询中包含了被索引的键.实 ...
- Mongodb 笔记03 查询、索引
查询 1. MongoDB使用find来进行查询.find的第一个参数决定了要返回哪些文档,这个参数是一个文档,用于指定查询条件.空的查询会匹配集合的全部内容.要是不指定查询,默认是{}. 2. 可以 ...
- MongoDB 学习笔记之 TTL索引,部分索引和文本索引
TTL索引: TTL集合支持mongodb对存储的数据进行失效时间设置,经过指定的时间段后.或在指定的时间点过期,集合自动被mongod清除.这一特性有利于对一些只需要保存一定时间的数据信息进行存储, ...
- mongodb笔记(三)
1.删除文档(remove()函数) 在执行remove()函数前先执行find()命令来判断执行的条件是否正确,这是一个比较好的习惯. 语法: db.collection.remove( <q ...
随机推荐
- 【CSAPP笔记】14. 异常控制流和进程
从给处理器加电,到断电为止,处理器做的工作其实就是不断地读取并执行一条条指令.这些指令的序列就叫做 CPU 的控制流(control flow).最简单的控制流是"平滑的",也就是 ...
- lintcode-517-丑数
517-丑数 写一个程序来检测一个整数是不是丑数. 丑数的定义是,只包含质因子 2, 3, 5 的正整数.比如 6, 8 就是丑数,但是 14 不是丑数以为他包含了质因子 7. 注意事项 可以认为 1 ...
- Scala入门系列(三):数组
Array 与Java的Array类似,也是长度不可变的数组,此外,由于Scala与Java都是运行在JVM中,双方可以互相调用,因此Scala数组的底层实际上是Java数组. 注意:访问数组中元素使 ...
- [BUAA_SE_2017]提问回顾
提问回顾 学期初疑问回答 学期初疑问博客 教材中说,PM在衡量需求时需要方方面面的能力与研究.可是,当下许多互联网IT公司只承担外包业务,即客户给什么需求就实现什么需求,甚至可能不要求其它先进的功能. ...
- HDU 2061 Treasure the new start, freshmen!
http://acm.hdu.edu.cn/showproblem.php?pid=2061 Problem Description background:A new semester comes , ...
- sqlserver 修改表字段长度
ALTER TABLE Table1 ALTER COLUMN column1 VARCHAR(255)
- 【vue】import的使用
以下是vue默认模板结构,自动加载HelloWorld (1)@ 等价于 /src 这个目录,避免写麻烦又易错的相对路径,是在webpack.base.config.js里面配置好别名 (2)impo ...
- [华三] IPv6技术白皮书(V1.00)
IPv6技术白皮书(V1.00) http://www.h3c.com/cn/d_200802/605649_30003_0.htm H3C S7500E IPv6技术白皮书 关键词:IPv6,隧道 ...
- Java override 和 overload 的区别和联系
方法的重写(Overriding)和重载(Overloading)是Java多态性的不同表现.重写(Overriding)是父类与子类之间多态性的一种表现,而重载(Overloading)是一个类中多 ...
- ZK Leader选举
1.Zookeeper节点状态LOOKING:寻找Leader状态,处于该状态需要进入选举流程LEADING:领导者状态,处于该状态的节点说明是角色已经是LeaderFOLLOWING:跟随者状态,表 ...