本文写于2019年11月,是原本发布在公司内网的一篇水文
引子
前不久听了一场关于mongodb的内部分享会,想以此次分享所得,结合自己日常开发中对于mongodb的理解做个总结。
基本知识
MongoDB is a non-relational database developed by MongoDB, Inc. MongoDB stores data as documents in a binary representation called BSON (Binary JSON). Related information is stored together for fast query access through the MongoDB query language. Fields can vary from document to document; there is no need to declare the structure of documents to the system – documents are self-describing.
关于mongodb的介绍有各种各样的说法,这里我直接摘抄了官方文档的一段表述,并把我认为重要的部分用加粗标了出来。
非关系型数据库,二进制JSON文档存储,不需要申明表结构。这些特点是MongoDB自身独特的地方,也是其立足的根本,之后会有详细的说明。
与关系型数据库对比
各传统关系型数据库之间也存在不小的差异,大而泛的对比显然行不通,所以这里拿比较常用的mysql数据库来与mongodb做对比。
数据库 | MySQL | MongoDB |
---|---|---|
模型管理 | mybatis entity生成,每次表结构变动需要重新生成 | 基于spring data注解,一个类对应一个collection,随时增删字段 |
扩展性 | 支持垂直分片,水平切分,分表后查询复杂度高 | 天然支持分片,分片后不影响查询逻辑 |
事务支持 | innoDB支持ACID | 4.X版本后支持事务 |
数据库设计 | 范式+反范式 | 范式+反范式 |
查询语句 | mongoDB查询语句 | SQL语句 |
读写性能 | – -- | 读取速度优于MySQL |
其他 | 支持字段自增 | 支持GridFs,适合存储敏感数据、小文件 |
关于这个对比的表格,有几点需要做补充说明。
1.mongodb的事务。
mongodb使用的存储引擎WiredTiger是支持事务的,但是在4.0之前的mongodb中没有提供对事务的支持,4.0版本之后提供了对事务的支持,而在不久之前发布的4.2版本之后才提供了对分布式事务的支持。
2.读取性能
我认为抛开使用场景谈性能都是耍流氓。mongodb和mysql在设计上都使用了可插拔的存储引擎设计,根据需求可选择不同的引擎使用。而在默认的配置下,mongodb使用的是WiredTiger存储引擎,mysql使用的是innodb作为默认存储引擎。wiredTiger的热缓存技术,使其能在内存中缓存大量数据,减少了对磁盘的访问次数。高度可伸缩的并发读写器也是mongodb在很多场景下性能高于mysql的原因之一。
但是事情并不绝对,部分极端场景下,由于优化的差异可能会出现mysql的查询速度与mongodb持平甚至高于的情况。
适用场景
存储结构相对灵活,由Key-Value键值对来支持丰富的数据结构,元素可以是多种数据类型甚至是嵌套子文档。这里贴一段严选大佬之前发的文章里的话。
举电商领域为例,网易严选上卖的上衣和裤子两种商品,除了有共同属性,如产地、价格、材质、颜色等外,还有各自有不同的属性集,如上衣的独有属性是肩宽、胸围、袖长等,裤子的独有属性是臀围、脚口和裤长等。这些独有属性可以直接以JSON子文档的方式嵌套在商品这个文档中,一次查询直接获取全部内容,不需要进行多表join;MongoDB文档的另一大特点是模式灵活:不同文档相同key的value类型可以是整形也可以是字符串等其他类型,不同文档可以有不同的key,比如有些商品有折扣字段,可以定义不同会员等级的不同折扣。在电商配套的物流领域,可以将一个快递的物流信息直接嵌套在以商品id为唯一索引的文档中,一次查询就可以获取完整的快递流向信息。MongoDB查询还提供了非常丰富的操作符,在查询中组合使用效率倍增。
使用优势
文档的灵活还体现在对多样或多边的业务场景的支持。例如在快速迭代的产品中,如果需要对某张表的字段进行修改,不需要像mysql使用DDL语句,而是可以直接在代码中修改,交给ORM框架去完成。
大数据支持性。分片(sharding)的机制使得其水平扩展能力极强,在对于需要保存海量数据的应用场景下能力远高于传统关系型数据库。
实际使用
在之前开发某个服务的过程中中使用了mongodb来存储接口中获取的数据信息。简单介绍下这个项目的场景,是从用户侧通过接口获取应用数据来检测应用当前状态,检测规则是模拟用户判断行为,对用户会有疑问的数据提前发现排查和处理。
因为是从接口上获取数据,拿到的就是一个json串,如果用传统的关系型数据库来存这部分数据,只能将整个json串转成string存,或者是按照特征分成几个字段,这样存会出现的问题就是不好对这个json串进行检索,如果要对响应内容进行检索和统计,会非常艰难。而使用mongodb,保存的数据完全按照json串的结构,如果要针对某些字段做检索,可以直接通过mongodb的查询语句进行,十分方便。