2022 开发岗 SQL 和 NoSQL 数据库选择指南

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 MongoDB,通用型 2核4GB
简介: 本文将通过对比 MySQL 与 MongoDB 的一些性能和特点,来简单刨析结构化数据库与文档性数据库,从而给大家以后在生产环境中数据存储介质的选择提供一些参考。

1.gif

本文将通过对比 MySQL 与 MongoDB 的一些性能和特点,来简单刨析结构化数据库与文档性数据库,从而给大家以后在生产环境中数据存储介质的选择提供一些参考。


前言


SQL 的全称是 Structured Query Language(结构化查询语言),主要用来操作结构化数据库的增删改查与结构的定义。其中结构化的数据库主要有 MySQL,Oracle,SQL Server 等。其中 MySQL 在国内使用非常广泛,其以开源、免费闻名于世界;并且我们公司生产环境也多以 MySQL 5.7 为主。


而 NoSQL 的意思是说 Not Only SQL,就是说不仅仅是 SQL,我还有别的功能;这可能与大多数人的认知有些偏差。其中的代表有 K/V 存储数据库像 Redis,levelDB 等;文档形数据库像 MongoDB,DynamoDB(Amazon),CouchDB 等;列族数据库像 HBase、Cassandra 等。最符合其 Not Only SQL 身份的是文档形数据库,其主要用来存储非结构化的数据,同时也兼顾了存储结构化数据的功能,相当于对现有结构化数据库的一种扩展。其中代表的数据库有 MongoDB,DynamoDB(Amazon),CouchDB 等。在生产环境当中,免费的以开源的 MongoDB 占大多数,而付费的 DynamoDB 也占据一片江山。本文讨论的 NoSQL 也将以文档形数据库中的 MongoDB 为主。


本人在集团生产环境中使用了阿里云的 MongoDB 已有近两年的时间,其中也积累了一些经验;同时也经历了 MongoDB 从 3.X 到 4.X 版本升级带来的新特性。本文将通过对比 MySQL 与 MongoDB 的一些性能和特点,来简单刨析结构化数据库与文档性数据库,从而给大家以后在生产环境中数据存储介质的选择提供一些参考。


图片.pngimage.gif

一些术语类比


为了便于对 MongoDB 有个大致的概念,下表中将 MongoDB 与 MySQL 功能相同、相近的概念进行了列举:


MongoDB MySQL
数据库 Database 数据库 Database
集合 Collection 表 Table
文档 Document 记录行 Row
字段 Field 列 Column


数据存储形式


以存储学生信息为例,假设要存储 学号,姓名,性别,生日,入学时间,年级 等信息为例。(同时也加上我司特色的 gmtCreate,gmtModified 字段,以及自增主键 id)


在 MySQL 当中会以如下的形式存储,当然需要提前把表建好(在这里省略掉),数据的存储形式类似于一个 Excel 表格:


id gmt_create gmt_modified student_number last_name fitst_name full_name gender dateofbirth register_time grade
666 2018-02-04 11:22:33 2021-02-05 01:02:03 123505666 敬亭 白敬亭 M 1993-10-15 2018-09-01 08:08:08 3
888 2021-02-05 11:22:33 2022-02-06 01:02:03 123505888 今麦 赵今麦 F 2002-9-29 2021-09-01 08:08:08 1


而在 MongoDB 当中,不需要提前创建表。其数据会以如下的形式存储,类似于一个 JSON:



[
    {
        "_id" : "5a760bf9e1d51a18bebcf5e1",
        "gmtCreate" : "2018-02-04 03:22:33.666",
        "gmtModified" : "2021-02-04 17:02:03.888",
        "studentNumber" : "123505666",
        "lastName" : "白",
        "firstName" : "敬亭",
        "fullName" : "白敬亭",
        "gender" : "M",
        "dateOfBirth" : "1993-10-15",
        "registerTime" : "2018-09-01 00:08:08.686",
        "grade" : 1,
        "_class" : "com.alibaba.xxx.xxx.StudentDO"
    },
    {
        "_id" : "601cd6196b919e6b328d8888",
        "gmtCreate" : "2021-02-05 13:22:33.778",
        "gmtModified" : "2022-02-05 17:02:03.345",
        "studentNumber" : "123505888",
        "lastName" : "赵",
        "firstName" : "今麦",
        "fullName" : "赵今麦",
        "gender" : "F",
        "dateOfBirth" : "2002-9-29",
        "registerTime" : "2021-09-01 08:08:08.225",
        "grade" : 1,
        "_class" : "com.alibaba.xxx.xxx.StudentDO"
    }
]


实际上,它是以一个叫 BSON,一种二进制的 JSON 形式存储的。


基本操作语法


以基本的增删改查为例,两种查询语法确实有很大的区别。


 增加记录


INSERT INTO student (gmt_create, gmt_modified, student_number, last_name, fitst_name, full_name, gender, date_of_birth, register_time, grade) VALUES (now(), now(), "123505666", "白", "敬亭", "白敬亭", "M", "1993-10-15", "2018-09-01 08:08:08", 3);



db.student.insert(
    {
        "gmtCreate" : "2018-02-04 03:22:33.666",
        "gmtModified" : "2021-02-04 17:02:03.888",
        "studentNumber" : "123505666",
        "lastName" : "白",
        "firstName" : "敬亭",
        "fullName" : "白敬亭",
        "gender" : "M",
        "dateOfBirth" : "1993-10-15",
        "registerTime" : "2018-09-01 00:08:08.686",
        "grade" : 1
    }
);


 删除记录


DELETE FROM student WHERE id = 888;


db.stduent.deleteMany({
    "_id" : "601cd6196b919e6b328d8888"
});


 修改记录


UPDATE student SET grade = 4 WHERE id = 888;


db.student.update(
    {
        "_id" : "5a760bf9e1d51a18bebcf5e1"
    },
    {
        $set : {
            "grade" : 4
        }
    }
)


 查询记录


SELECT * FROM student WHERE full_name = "赵今麦";


db.student.find({
    "fullName" : "赵今麦"
})


可以看出,MongoDB 的语法其实也并不复杂,整个操作就像是在写一个描述对象的 JSON,外加一些操作的关键字。


使用感受对比


  1. MongoDB 非常适合敏捷开发。首先它不需要创建表,再加上我自己封装了一套 DAO 框架,大概创建一套 DO 对象的增删改查只要继承对象、实现接口,整个增删改查代码只要在 300 行(包含 DO 本身)之内就可以搞定,最多 30min 内搞定。而 MySQL 需要到集团 DMS 上去先创建一个结构设计工单,然后把数据库结构同步到线上。再用 IDEA 中的插件把 SQL,Mapper 等生成,或者自己写也行。一套 DO 对象的增删改查代码轻轻松松上千行,保守估计耗时要 1h。有的时候碰上双 11、618 等 “良辰吉日” ,审批等个 1 - 2 天也是有可能的。
  2. 第二点 MongoDB 在开发时非常方便。虽然很多时候在开发之前都会把领域模型,数据库表设计好,但是不免有考虑不周的地方:例如在开发过程中要加个字段、删个字段、改个字段名、或者改个字段类型之类的。改字段名、删字段等在集团 MySQL 中做了限制,基本上就别想了。而增加字段,改字段类型还要走一遍前面 DDL 流程,然后再去改 Mapper 等文件,非常麻烦。而如果用 MongoDB 的话,直接改一下 DO 对象,查询对象就好,基本上是分分种就能搞定。同时由于 MongoDB 的 JSON 格式,多一个字段,少一个字段,也不会在查询中报错,顶多是对于老数据来说,新加的字段没有值而已。
  3. 在高端玩法上面,MongoDO 对多态支持的非常好。有的时候一个基类有多个衍生类需要存储,它这种文档形式的存储天然可以根据不同的衍生类扩展不同的字段。同时它的文档里面存有一个 "_class" 字段来标识查询出来的数据要反序列化成哪一个对象的,并且 MongoDB 的 Spring 底层框架已经封装得很好。所以查出来的衍生类都可以无感知的用基类来接收而不用多写一行代码,同时再配合使用策略模式使用,简直完美。反观 MySQL 其实也可以实现,要在表中增加一个字段来记录衍生类的类型,同时自己要写一些 TypeHandler 来处理转换成对应的衍生对象,我以前有使用过,算是比较麻烦的。
  4. 另一个高端玩法,MongoDB 支持使用对象里面包含的对象中的字段来建索引,同时也支持将对象当中的数组元素来建索引。比如说在实践中有这种场景,在开发的时候业务侧信心满满的跟你说这个字段肯定不会用来查询,然后你也很自信把它存储在了扩展字段或者 JSON 里面。而过了两个月,他又跑过来跟你说,我觉得这个字段筛选有用,能不能支持一下查询。如果这个时候使用 MySQL 简直要疯了,而使用 MongoDB 的化,只需要在 "xx.yy" 上面加个索引即可;另外在数组元素中加索引,MySQL 是想都不敢想的。另一方面,在 MySQL 中存储时,对象可能平铺的更开一些,一般遇到 "xx.yy",'"xx.zz" 都会展开成两个字段放在最外层。而 MongoDB 可以使用与原始 DO 甚至 DTO 对应的存储形式,查询结果看起来更直观一些。
  5. 很多人提到 MongoDB 都会说它不支持事务,那是在 4.0 之前的事了。MongoDB 在 4.0 开始支持事务,在 4.2 开始支持分片的事务,Spring 的 @Transactional 注解也是可以使用的。其实我个人理解,事务对性能是有一定损耗的,B 端业务使用肯定没问题,在 C 端大流量场景下,除非有强一致性要求,能不用就别用。同时一些消息中间件,定时任务也可以用来保证数据的最终一致性。
  6. 在 MySQL 中的横向扩展例如分库分表,在 MongoDB 当中当然也是支持的,并且支持得更好。因为 MongoDB 的开发初衷就是为了更好得支持分布式系统,所以这种在设计初都被考虑进去过。它采用了一种叫分片的形式,用多个 mongos 节点服务器作为代理节点,后面跟的是多个 shard 节点,外加配置服务器 config server。分片的规则都在 shard 节点配置好,对客户端其实是无感知的。
  7. 在关系型数据库支持的级联查询以及 MySQL 风靡一时的存储过程,我也做过一些调研,在 MongoDB 当中都是支持的,不过确实实现起来会比 MySQL 复杂一些。但是话说回来,在生产环境当中还是不太推荐使用级联查询,关联多张表(或多个文档)的查询还是分多次来比较好。另外存储过程现在也基本上没人使用;当初某个互联网公司有人在 MySQL 存储过程中去连接另一个数据库进行查询的时代也过去了(大家千万别这样用,也别说我说的 LOL)。
  8. 但是有一点,目前集团对 MongoDB 所做的一些监控,报警之类的并没有 MySQL 齐全,在使用的时候可能需要投入一些时间来运维。举个例子如果一个慢查询,在 MySQL 当中你不改可能过两几天就有人来催你了;但是在 MongoDB 当中,你需要自己去阿里云云控制台,查看监控来分析、发现问题。


性能测试


在这里先简单做一个 MongoDB 在高并发场景下的性能测试,以上面事例中的对象为例。因精力有限,此次只做写入和索引查询的性能测试,更丰富的测试在后面的文章中呈现。


 数据库服务器配置


采用单机运行,16核 CPU,128G 内存,1T SSD。机器是借来进行测试的,基本可以达到单台数据库服务器性能的天花板。


 并发写入


插入数据量 (条) 耗时 (ms) 平均QPS
100 4 25000
1000 26 38462
10000 232 43103
100000 2228 44883
1000000 22632 44185



PS:进行多组测试,每组测试插入不同的数据量,每组测试中对相同的数据量进行多轮测试,取每轮结果的平均值作为该组测试的结果。每次插入采用 JAVA 代码随机生成单条上述对象并进行插入,采用并多线程提升并发量。每组数据测试前将表中数据清空,但每轮测试时保留当前数据不清空。例如:测量 10W 并发插入时,先将数据清空,然后连续调用插入 10 次,期间不清空数据,取每次耗时的平均值。


 并发索引查询


查询数据量 (条) 耗时 (ms) 平均QPS
100 3 33333
1000 24 41667
10000 108 92592
100000 835 119760
1000000 8315 120264


PS:在并发查询测试之前按照上面测试流程插入 100W 条随机数据,且在 studentNumber 字段上面创建索引。每组测试中在一定范围内随机 studentNumber 值来进行并发查询相应的次数;每组测试中进行多轮测试,取耗时结果的平均值。

总结


本文主要介绍了 MongoDB 数据库的基本使用,以及其与关系型数据库 MySQL 的对比;包括一些个人在使用当中的见解和感受。同时进行了 MongoDB 在高并发场景下的简单性能测试。从单台数据库服务器看来,MongoDB 有很高的写入、查询性能;如果采用多台服务器组成副本集(类似于 MySQL 的读写分离),或者分片(类似于 MySQL 的分库分表),将会有更好的性能。


个人建议,如果新上线的项目,特别是要快速上线,敏捷开发,建议可以在有限的精力下尝试使用 MongoDB;而如果是以前使用 MySQL 开发的老项目,建议还是继续使用 MySQL,因为这时不会带来质的飞跃,并且还是一定的数据迁移的成本。


扩展资料


  1. 阿里云 MongoDB 产品(地址:https://www.aliyun.com/product/mongodb
  2. 前 Oracle 首席工程师怒喷:MySQL 是“超烂的数据库”,建议考虑 PostgreSQL(地址:https://blog.csdn.net/j3T9Z7H/article/details/121986807
  3. 一种NewSQL:TiDB 简介 | PingCAP Docs(地址:https://docs.pingcap.com/zh/tidb/v4.0


团队介绍


我们是大聚划算技术团队。使命:让货品和心智运营变得高效且有确定性!愿景:与运营、产品合力,打造最具价格优惠心智的购物入口,最具爆发性的营销矩阵。职责:负责支持聚划算、百亿补贴、天天特卖等业务。我们聚焦优惠和选购体验,通过数智化驱动形成更有效率和确定性的货品运营方法论,为消费者提供精选和极致性价比的商品,为商家提供更具爆发确定性的营销方案。这是一只极具业务 scene,又具备复杂业务系统架构和设计经验的团队。简历投递至:洋轩 michael.lsy@alibaba-inc.com

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
4天前
|
SQL Oracle 关系型数据库
sql语句创建数据库
在创建数据库之前,请确保你有足够的权限,并且已经考虑了数据库的安全性和性能需求。此外,不同的DBMS可能有特定的最佳实践和配置要求,因此建议查阅相关DBMS的官方文档以获取更详细和准确的信息。
|
4天前
|
SQL 存储 关系型数据库
数据库开发之图形化工具以及表操作的详细解析
数据库开发之图形化工具以及表操作的详细解析
21 0
|
15天前
|
SQL 人工智能 算法
【SQL server】玩转SQL server数据库:第二章 关系数据库
【SQL server】玩转SQL server数据库:第二章 关系数据库
52 10
|
4天前
|
SQL 存储 关系型数据库
数据库开发之mysql前言以及详细解析
数据库开发之mysql前言以及详细解析
14 0
|
15天前
|
SQL 算法 数据库
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
88 6
|
1天前
|
缓存 NoSQL 关系型数据库
在Python Web开发过程中:数据库与缓存,MySQL和NoSQL数据库的主要差异是什么?
MySQL与NoSQL的主要区别在于数据结构、查询语言和可扩展性。MySQL是关系型数据库,依赖预定义的数据表结构,使用SQL进行复杂查询,适合垂直扩展。而NoSQL提供灵活的存储方式(如JSON、哈希表),无统一查询语言,支持横向扩展,适用于处理大规模、非结构化数据和高并发场景。选择哪种取决于应用需求、数据模型及扩展策略。
10 0
|
2天前
|
SQL Java 数据库连接
Java从入门到精通:2.3.2数据库编程——了解SQL语言,编写基本查询语句
Java从入门到精通:2.3.2数据库编程——了解SQL语言,编写基本查询语句
|
4天前
|
SQL 缓存 数据库
sql 数据库优化
SQL数据库优化是一个复杂且关键的过程,涉及多个层面的技术和策略。以下是一些主要的优化建议: 查询语句优化: 避免全表扫描:在查询时,尽量使用索引来减少全表扫描,提高查询速度。 使用合适的子查询方式:子查询可能降低查询效率,但可以通过优化子查询的结构或使用连接(JOIN)替代子查询来提高性能。 简化查询语句:避免不必要的复杂查询,尽量使SQL语句简单明了。 使用EXISTS替代IN:在查询数据是否存在时,使用EXISTS通常比IN更快。 索引优化: 建立合适的索引:对于经常查询的列,如主键和外键,应创建相应的索引。同时,考虑使用覆盖索引来进一步提高性能。 避免过多的索引:虽然索引可以提高查询
|
4天前
|
SQL XML 数据库
sql导入数据库命令
在SQL Server中,数据库导入可通过多种方式实现:1) 使用SSMS的“导入数据”向导从各种源(如Excel、CSV)导入;2) BULK INSERT语句适用于导入文本文件;3) bcp命令行工具进行批量数据交换;4) OPENROWSET函数直接从外部数据源(如Excel)插入数据。在操作前,请记得备份数据库,并可能需对数据进行预处理以符合SQL Server要求。注意不同方法可能依版本和配置而异。
|
7天前
|
NoSQL MongoDB Redis
Python与NoSQL数据库(MongoDB、Redis等)面试问答
【4月更文挑战第16天】本文探讨了Python与NoSQL数据库(如MongoDB、Redis)在面试中的常见问题,包括连接与操作数据库、错误处理、高级特性和缓存策略。重点介绍了使用`pymongo`和`redis`库进行CRUD操作、异常捕获以及数据一致性管理。通过理解这些问题、易错点及避免策略,并结合代码示例,开发者能在面试中展现其技术实力和实践经验。
129 8
Python与NoSQL数据库(MongoDB、Redis等)面试问答