MongoDB 全方位对比 MySql
1.介绍
可以说,作为IT专业人员,我们正处于数据管理时代的黄金时代。随着我们的软件系统变得越来越复杂且分布更广,受到无数可扩展性和可用性要求的推动,多年来使用的传统解决方案开始落后。
本教程的目标是提供两种数据管理解决方案的公平概述:由MySQL代表的成熟和广泛使用的关系数据库以及该块MongoDB上的新成员,后者又代表新一代数据存储。这决不是与最终明确的赢家的战斗。相反,其目的是通过探讨MySQL和MongoDB的功能,帮助开发人员做出选择并找到适合他们应用程序的正确选择,讨论每个人的不同保证和限制。

2. RDBM系统的优势
数据管理软件的发展历史并不是一个特别令人兴奋的时间。在相当长一段时间内,关系数据库管理系统发挥了领导作用,多年来,选择很明显,无论是MySQL,PostreSQL还是Oracle,仅举几例。SQL(及其特定于供应商的方言)是查询关系数据存储的事实上的标准,根据定义,每个后端软件开发人员都必须学习和理解其至少一些基本知识。直到最近,当一系列新的数据管理系统出现时,它的表现非常出色,这种现象也被称为NoSQL(或非唯一SQL)运动。

3. NoSQL运动的新时代
现代软件系统在数据量和请求/事务吞吐量要求方面面临的挑战表明,关系数据存储常常成为瓶颈,因此对整体系统可扩展性施加限制。传统上,解决这个问题的方法只是购买一个更大的盒子(所谓垂直可扩展性),但是在某些时候,付出的代价变得非常高,使得整个系统的代价非常昂贵和不切实际。
业界正在积极研究构建复杂分布式系统的更便宜的方法,而不是利用横向可伸缩性。它还意味着提供关系数据存储的替代方案,并可以水平扩展。那一刻,当NoSQL运动开始时。
4.表格与文档vs图表与键/值
一个关系型数据模型代表的元组和关系上的所有数据(更好地称为表)。结构化数据非常适合这种模式,很长一段时间没有其他可行的替代方案存在。随着NoSQL的运动,许多替代数据模型被开发出来,诞生了大量的专用数据存储系统。
在NoSQL的解决方案,可以在几个不同的类别进行分类。文档数据存储设计用于存储,查询和管理文档(半结构化数据)。这个类别中较成熟的代表包括CouchDB,Couchbase,MongoDB,OrientDB和HyperDex。键/值数据存储设计用于存储,查询和管理关联数组(也称为字典或散列)。
这个类别中使用最广泛的代表包括DynamoDB,FoundationDB,HyperDex,MemcacheDB,Redis,Riak,Aerospike和OrientDB。图形数据存储设计用于高效地存储和操作图形结构。这一类的着名代表包括Neo4J,InfiniteGraph,GraphBase和OrientDB。最后但并非最不重要的是,宽列数据存储正在采用混合方法(结合关键/值数据存储的一些特性和传统的关系数据存储)。这一类最先进的代表包括Accumulo,Cassandra和HBase。
请注意,上面介绍的不同NoSQL数据存储列表远远没有完成,它只包含最知名和广泛使用的名称,但还有更多。

5. MySQL和MongoDB:有意识的决定
引言足够了,让我们继续讨论更实用的东西。在本教程的这一部分,我们将使用MySQL和MongoDB来看看应用程序开发过程的各个方面,同时也花费一些时间来讨论部署和监视。我们的目标是讨论每个数据存储所做的权衡和设计决策,并分析它们如何改变我们开发应用程序的方式。另外,本教程的另一个目的是在考虑到应用程序体系结构,数据访问模式和存储需求的情况下,协助做出决定,何时MongoDB可能比MySQL更好(反之亦然)。
正如我们现在所说的,MongoDB是一个文档数据存储。它存储分组到集合中的JSON样式的文档。在MongoDB数据模型层次结构的顶部是一个数据库(请参阅官方文档以获得全面的详细信息)。目前的生产就绪版本的MongoDB是3.0.4。
从另一方面来说,MySQL是关系数据存储。数据存储在包含列的表格中。表格被分组到数据库中(请参阅官方文档以获得全面的详细信息)。当前生产就绪版本的MySQL是5.6.25。
MySQL支持多个存储引擎,每个存储引擎都有自己的目的,并且具有其他存储引擎不具备的一些功能。在本教程中,我们假设使用InnoDB存储引擎,因为它是默认和最通用的引擎,推荐使用,除了专用用例。
5.1。强制模式与无模式
作为关系数据存储的MySQL需要一个严格的数据模型模式:所有的表都应该使用定义的列来创建。只有这样才能使用SQL语言存储和查询数据。由于每次需要修改数据模型时都会使开发和部署过程复杂化,因此应该首先更改模式,然后再迁移数据。下面是使用MySQL shell和SQL语言创建新数据库,新表并向其中插入一行所需的典型步骤示例:

相比之下,MongoDB不会对集合中存储的文档施加任何模式。应用程序负责处理这个问题,MongoDB限制的唯一事情就是支持的数据类型。它显着加快了开发过程,因为MongoDB可以立即用于存储任何形状的JSON文档。
文档的结构可以随着时间的推移而发生变化,并且不同代的文档可以共存于同一个集合中。如果需要,应由开发人员决定如何执行数据清理或迁移。让我们来看看如何使用MongoDB外壳完成创建新数据库,新集合和向其中插入一个文档的相同步骤:

值得一提的是,即将发布的5.7版本的MySQL(目前处于候选版本阶段)引入了本机JSON支持。随着这种新的JSON数据类型的引入,将有可能在MySQL中结合强制模式和无模式数据。

5.2。标准化与复制
关系数据库世界中的规范化是组织表以最小化数据冗余的过程。它涉及将表分解为不冗余(和更小)表而不丢失数据。它还假定在旧表中定义引用新键的主键的外键。例如,这是在MySQL中创建两个表的方式,books表引用authors表:

MongoDB的规范化已经过时了。相反,仔细的数据建模和一定程度的数据重复是最大限度地利用文档数据存储的方法。它也成为应用程序的责任来决定数据重复的级别并在修改的情况下保持所有数据片段同步。例如:

5.3。关系与参考
在规范化数据库中,SQL中的JOIN子句通常用于合并来自两个或多个MySQL表的记录(还有其他技术,但总体上它们导致相同的结果)。例如:
SELECT * FROM books b INNER JOIN authors a ON a.id = b.author_id;
MongoDB支持文档引用,但不支持连接:为了解析引用,应该执行额外的一个或多个查询(导致关系世界N + 1查询问题臭名昭着)。例如,在下面的代码片段中,我们从书籍集合中插入对作者集合的引用,而不是嵌入作者的详细信息:

必要的往返行程是支付无模式灵活性的代价。但是,正如我们在规范化与复制部分中已经提到的那样,某些数据重复级别和对数据访问模式的仔细分析可能会缓解这个问题。

5.4。交易与原子更新
交易是数据管理系统根据其数据执行的工作的逻辑单元。事务的重要性被封装到它的基本属性中:事务必须是原子的,一致的,隔离的和持久的(也被称为ACID模型)。MySQL是一个完全事务关系数据存储,使其成为不能容忍数据丢失或不一致的任务关键型应用程序的完美选择。但是,事务不是免费的:它们大大限制了数据存储的水平可伸缩性,MySQL也不例外。
MongoDB不支持事务保证。相反,它支持单个文档级别的原子更新。这意味着当一个更新操作修改多个文档时,每个文档的修改都是原子的,但整个操作不是原子操作,其他操作可能会交织。值得一提的是,可以在MongoDB之上实现类似事务的语义(使用两阶段提交技术),但它需要非常复杂的实现。
5.5。SQL vs JSON
SQL是一种特殊用途的编程语言,用于管理关系数据库管理系统中保存的数据。它是MySQL支持的唯一查询语言,并增加了一些特定于供应商的扩展。尽管简单,但SQL是一种非常强大的语言,它基本上由两部分组成:数据定义语言(DDL)和数据操作语言(DML)。我们已经看到了很多例子,但让我们看看从表格中选择行的最简单也是最有用的例子:
SELECT * FROM books; SELECT * FROM books WHERE title LIKE "%MySQL%";
在MongoDB中,所有东西都是一个文档,用JSON表示。MongoDB没有专门的语言来管理文档,而是采用了非常不同的方法。文档操作或查询使用非常丰富的一组操作符来描述,这些操作符使用JSON结构相互组合,与其他任何文档一样。这种统一的表示形式非常强大,表达和易于理解,而且不需要学习另一种编程语言。大多数操作员都是不言自明的直观的,例如:

5.6。存储过程与脚本
存储过程是关系数据存储的服务器端可用的一种特殊例程。存储过程可以用不同的编程语言实现,但大多数情况下,它们都是使用SQL或其特定于供应商的方言编写的,这是MySQL的情况。通常,存储过程通过在服务器上直接执行某些逻辑来帮助提高应用程序的性能,这就需要在服务器和客户端之间发送更少的信息。例如,下面是一个非常简单的MySQL存储过程:

MongoDB以服务器上执行JavaScript代码的形式支持服务器端脚本。这些服务器端脚本可能与存储过程相似,但实现不仅仅是简单的脚本,因为它支持map / reduce范式,最初由Google填充,并广泛用于大数据分析。本质上,通过提供map / reduce命令的脚本,可以跨多个MongoDB数据存储实例并行处理大型和超大型数据集。让我们看一下非常天真的map / reduce脚本示例,它可以计算出有多少书籍的标题中包含“MySQL”字符串:

与MySQL存储过程示例相比,MongoDB看起来过于冗长和复杂。然而,一旦map / reduce范例的概念变得更加清晰,这个例子将会看起来非常简单,为应用许多数据处理,探索和分析技术开辟了一个全新的前沿。
5.7。GROUP BY与聚合
在数据管理领域,聚合函数是一个函数,其中多个数据记录的值根据特定的聚合准则分组在一起,因此产生更重要的意义或度量的单个值。在SQL语言定义了一组用于执行聚合特定条款:GROUP BY和HAVING。标准分组函数集包括AVG(),COUNT(),MAX(),MIN(),STD(),SUM()。让我们看看MySQL shell中的GROUP BY示例:

MongoDB提供了一组专门的聚合操作,它处理文档并返回计算(或聚合)的结果。汇总操作将来自多个文档的值组合在一起,并且可以对分组数据执行各种操作以返回单个结果。MongoDB中的聚合可以通过两种方式完成:使用聚合管道或单用途聚合方法和命令。
让我们看看我们准备展示MySQL聚合的同一个例子,这次使用MongoDB的聚合管道:

我们在“ 存储过程与脚本”部分讨论过的map / reduce命令也可以视为一种聚合方式。

5.8。聚类和分片/分区
如今,数据量呈指数增长,数据存储的单一物理实例通常无法持续并以可接受的速度管理如此大量的数据。集群技术可以使许多个人计算实例一起工作。就数据存储而言,集群与数据分片/分区并行进行,这是一种将大量数据分散到多个数据存储实例的技术。
一段时间以来,MySQL已经可以在MySQL Cluster版本中使用,该版本声称是可写入扩展的实时ACID兼容事务数据存储。MySQL Cluster建立在分布式多主架构之上,支持自动分片/分区和水平扩展以提供读写密集型工作负载。
从历史上看,MySQL Cluster的信誉太复杂,很难配置,监视和维护。与独立的MySQL部署相比,数据模式的设计应考虑数据分片/分区,否则数据存储的性能将受到很大影响。最后,MySQL Cluster与常规的MySQL发行版相比有很多限制。
MongoDB文档数据存储使用分片群集的概念支持分片/分区。MongoDB分片/分区的强大之处在于它具有简单易用的配置。它横向很好地缩放,但有很多限制需要注意。

5.8.1。复制
复制是保持数据安全(通过将其复制到多个数据存储实例中)的关键技术,并且在许多情况下用于提高处理此数据的应用程序的可伸缩性和容错性。MySQL支持传统的主/从复制,默认情况下它是异步的,但是也可以使用半同步和延迟复制模式。
MongoDB通过引入副本集来处理复制。基本上,它是主/从复制,但MongoDB使用一点点不同的术语。称为主服务器的主服务器接收所有写入操作和从服务器,称为辅助服务器,从主服务器应用操作。副本集支持的最大功能之一是自动故障转移:当主节点不与副本集的其他成员进行通信时,副本集将尝试选择另一个成员以成为新的主节点。
公平地说,可以使用自动故障转移来配置MySQL主/从复制,但在MySQL社区中有一些关于此功能的疑虑和讨论。
5.9。全文搜索
由于很长一段时间,MySQL支持使用特殊类型的索引实现的全文索引和搜索。仅在自MySQL 5.6发布分支以来,才有可能在InnoDB存储引擎上提供全文索引支持,这一点很重要。
有趣的是,全文搜索的MySQL可以使用自然语言搜索(短语搜索),布尔搜索(搜索项的搜索)的哪里话来搜索可能被标记为“必须存在”或“必须是不存在的”,并查询扩展搜索(对自然语言搜索进行轻微修改)。但是,目前全文索引在群集MySQL部署中不受支持(请参阅Clustering and Sharding / Partitioning部分以获得关于MySQL Cluster的简要讨论)。让我们看看一个简单的例子:

不久前在MongoDB中引入了全文搜索支持。与MySQL类似,它使用字符串内容(或字符串数组)的特殊类型的索引来实现。MongoDB也支持短语搜索,术语搜索和布尔搜索作为这些的组合。它很容易使用和优雅实施的功能,但不是没有限制。不幸的是,目前MongoDB不能控制指定字段的子集来执行全文搜索:它总是匹配全文索引中包含的所有字段。让我们来看看MongoDB全文搜索的实际操作:

5.10。发展
当涉及到开发时,MySQL提供了大量的连接器,可以用来从您选择的大多数主流编程语言与服务器进行通信。关于Java开发,MySQL包含一个符合JDBC 3.0和JDBC 4.0规范的JDBC驱动程序。
虽然很少遇到使用直接JDBC接口与关系数据存储进行通信的代码(许多框架都是为了方便而构建的),但知道涉及的内容是很好的。让我们看看下面的代码片断,它连接到MySQL并执行一条SELECT语句:

它看起来很冗长并且充满了异常处理。MongoDB反过来拥有丰富的驱动程序生态系统,除主流语言外,还包括Erlang,Go,Node.js和Scala的驱动程序。MongoDB有自由提出自己的规范,正在开发下一代驱动程序,并快速地将现有实现与业内最新趋势相适应(ReactiveMongo:MongoDB的ReactiveMongo:ReactiveMongo的非常好的例子) 。
举一个例子,让我们看看使用Java和Morphia驱动程序连接到MongoDB的一种方法(假设我们有Book和Author数据模型类):

从历史上看,Java中的JSON支持是非常好的,因为它提供了丰富的社区支持库,从而使JSON文档转换为Java类(和后面)毫不费力。
如果说Java社区已经开发了相当多的不同的对象关系映射框架(ORM)来从低级JDBC接口中抽象出来是不公平的,这实际上可以像MongoDB的例子那样简洁地编写代码。然而,理解它们会增加现有应用程序的复杂性非常重要。
5.10.1。部署
双方的MySQL和MongoDB的可在大多数主要操作系统。在大多数情况下,MySQL是从特定于平台的软件包安装的,并且需要对系统进行特权访问。虽然可下载的档案也可用,但根据操作系统,配置和版本(例如MySQL Cluster),安装可能会变得相当复杂和不直观(但可能不需要对系统进行特权访问)。
相反,MongoDB在大多数情况下是作为可下载的档案分发的,可以立即解压缩并使用。通过要求最低限度的配置,合理的默认值在这里扮演着重要的角色,只需运行MongoDB服务器并开始用文档填充数据存储。
可以公平地指出,随着集装箱化和Docker的部署程序(我们习惯于这样)的格局正在发生非常迅速的变化。从传统的基于软件包的发行版转移到预配置的容器,可以将可安装的软件包和下载 – 解压缩运行的模型展平:所有东西都会成为一个图像,作为独立的容器运行,并以毫秒为单位运行。
更不用说,许多云提供商(AWS,Cloud Foundry,Open Shift等)都提供了针对MySQL和/或MongoDB的软件即服务产品,可以处理所有配置,基础架构和可扩展性细节。
5.11。监测和诊断
显然,监控是任何数据存储管理过程的关键组成部分。有相当多的商业解决方案可用于监控您选择的数据存储,但让我们讨论可作为MySQL和MongoDB发行版一部分提供的解决方案。
MySQL有几种方法来执行监视和诊断。首先,它是SHOW ENGINE <ENGINE> STATUS命令。其次,MySQL支持性能模式,这是一个用于监视MySQL服务器执行的低级功能。最后,MySQL支持DTrace探测器(不受每个操作系统的支持),这些探测器旨在提供有关MySQL服务器内查询执行的信息以及在该过程中正在使用的系统的不同区域。
MongoDB发行版包含许多命令行实用程序,可以快速检索有关每个数据存储实例的性能和活动的统计信息。不仅如此,每个运行的MongoDB实例还提供了一个Web界面,通过简单的网页显示诊断和监控信息。最后,MongoDB包含许多命令,通过shell连接到数据库,以了解数据库的状态。
5.12。安全
MySQL使用基于权限的安全模型。所述的主要功能的MySQL的权限系统是认证用户,并与特权用户特定数据库上相关联(如CREATE,DROP,SELECT,INSERT,UPDATE,DELETE 等)。
到目前为止,MySQL特权系统不支持的东西很少:无法明确指定给定用户应该被拒绝访问,也无法指定用户有权创建或删除数据库中的表,但不能创建或者丢弃数据库本身。在传输层上,MySQL使用TLS v1.0协议使用SSL(安全套接字层)支持客户端和服务器之间的安全(加密)连接。
MongoDB的安全功能包括认证,授权和审计。其基础是基于角色的访问控制,具有灵活的特权。值得一提的是,MongoDB通过定义一组内置角色为用户定义的角色提供了基础。也可以使用TLS / SSL(传输层安全/安全套接字层)来加密所有MongoDB的网络流量,以确保它只能由预期的客户端读取。

5.13。权衡,而不是战斗
正如我们所看到的,MySQL和MongoDB具有相同的共同目标:为其用户提供全面的数据管理解决方案。然而,他们每个人接近这个目标的方式都非常不同。从一方面来说,我们看到了相当成熟和经过测试的关系数据存储。从另一方面来说,我们遇到了年轻但迅速成熟的文档数据存储,非常适合某些类型的现代Web应用程序。
正如本教程中多次提到的那样,这不是一场战斗,我们也不是在寻找赢家。相反,我们正在寻找更适合您应用需求的解决方案。更重要的是,异构数据存储基础设施比现在的例外变得更为常见:例如,MongoDB可能完全适合分析和报告需求,而MySQL可能存储计费事务。幸运的是,在本教程的帮助下,您将能够选择合适的工具来完成这项工作。
在很多方面,可以公平地说,MongoDB是为Web构建的:包含JSON,非常短的学习曲线,快速开发的基础,每个发行版都增加了新功能。MySQL是经过战斗测试,保守和旧时尚的,但随着关系数据商店尝试适应现代应用程序需求,事情正在发生非常快的变化。
5.15。MySQL或MongoDB?
已经有很多关于MySQL和MongoDB的文章。当MongoDB比MySQL更受欢迎时,使用一组建议来完成讨论会很好,反之亦然。
首先,如果你的数据对你的业务至关重要,MySQL很可能是一个更安全的选择:ACID属性是有原因的。但是每个应用程序都不同。内容管理系统,日志管理,分析,论坛和博客,事件存储,产品目录,库存管理,这些类型的应用程序都可能受益于MongoDB作为数据存储。
无模式数据模型是快速开发的推动因素:只需引入新属性,无需执行模式演变和数据迁移。可以说,但MongoDB处理文档和运行查询的风格更适合开发人员(而且,它不需要学习任何语言,如SQL)。与MySQL Cluster配置(和管理)相比,配置MongoDB的副本集和分片集群非常简单快捷。
现代架构模式正在推动将应用程序的读写路径分开(例如命令和查询责任分离或仅CQRS)。因此,应用程序可以通过MySQL提供写入路径的方式进行设计,但MongoDB可能是读取路径的数据存储器,其中数据片段被组合成有意义的文档。
5.16。MySQL和MongoDB:现在
值得一提的是,Twitter和Facebook两家公司成功运行了部分最大的MySQL部署。他们愉快地分享他们虽然众多的博客文章的经验:MySQL的在Twitter的,再看一下MySQL的在Twitter和孵化Mysos,Twitter将储存250亿如何鸣叫一个天使用MySQL,WebScaleSQL:将合作建立在MySQL的上游,等等。
从另一方面来说,随着越来越多的公司在越来越大规模部署它,MongoDB的采用日益增多。例如,eBay分享了我们如何构建eBay的第一个Node.js应用程序,而Craigslist 在Craigslist:1年后跟进了MongoDB。毫无疑问,我们将在未来看到更广泛的采用。
6.结论
在这个简短的教程中,我们尝试着看看两个非常流行的数据存储,由MySQL代表的传统关系数据库和由MongoDB代表的文档数据存储。我们简要介绍了其中的每个重要功能和数据保证,试图评估应用程序的可伸缩性和可用性如何受到影响。我们省略了很多低级固有的细节,因为MySQL和MongoDB都只值几本书。相反,我们做了一个高层次的概述,挑选了最有趣和最重要的领域。
相关推荐
-
PHP8种变量类型的详细讲解2025-02-22 00:32:24
-
php+apache 和 php+nginx的区别2025-02-22 00:21:27
-
PHP:与workerman结合实现定时任务2025-02-22 00:15:57
-
Nginx的Rewrite规则与实例2025-02-22 00:15:39
-
MySql中身份证字段的简单脱敏介绍2025-02-22 00:15:36