MySQL 与 MongoDB 1000 次读取

Posted

技术标签:

【中文标题】MySQL 与 MongoDB 1000 次读取【英文标题】:MySQL vs MongoDB 1000 reads 【发布时间】:2012-03-30 22:51:27 【问题描述】:

我对 MongoDb 感到非常兴奋,并且最近一直在测试它。我在 mysql 中有一个名为 posts 的表,其中大约 2000 万条记录仅在一个名为“id”的字段上建立索引。

我想将速度与 MongoDB 进行比较,我进行了一项测试,该测试将从我们庞大的数据库中随机获取并打印 15 条记录。我为 mysql 和 MongoDB 分别运行了大约 1,000 次查询,我很惊讶我没有注意到速度上有很大差异。也许 MongoDB 快 1.1 倍。这非常令人失望。有什么我做错了吗?我知道我的测试并不完美,但在阅读繁重的杂务方面,MySQL 与 MongoDb 相当。

注意:

我有双核 +(2 线程)i7 cpu 和 4GB 内存 我在 MySQL 上有 20 个分区,每个分区有 100 万条记录

用于测试 MongoDB 的示例代码

<?php
function microtime_float()

    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);

$time_taken = 0;
$tries = 100;
// connect
$time_start = microtime_float();

for($i=1;$i<=$tries;$i++)

    $m = new Mongo();
    $db = $m->swalif;
    $cursor = $db->posts->find(array('id' => array('$in' => get_15_random_numbers())));
    foreach ($cursor as $obj)
    
        //echo $obj["thread_title"] . "<br><Br>";
    


$time_end = microtime_float();
$time_taken = $time_taken + ($time_end - $time_start);
echo $time_taken;

function get_15_random_numbers()

    $numbers = array();
    for($i=1;$i<=15;$i++)
    
        $numbers[] = mt_rand(1, 20000000) ;

    
    return $numbers;


?>

测试 MySQL 的示例代码

<?php
function microtime_float()

    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);

$BASE_PATH = "../src/";
include_once($BASE_PATH  . "classes/forumdb.php");

$time_taken = 0;
$tries = 100;
$time_start = microtime_float();
for($i=1;$i<=$tries;$i++)

    $db = new AQLDatabase();
    $sql = "select * from posts_really_big where id in (".implode(',',get_15_random_numbers()).")";
    $result = $db->executeSQL($sql);
    while ($row = mysql_fetch_array($result) )
    
        //echo $row["thread_title"] . "<br><Br>";
    

$time_end = microtime_float();
$time_taken = $time_taken + ($time_end - $time_start);
echo $time_taken;

function get_15_random_numbers()

    $numbers = array();
    for($i=1;$i<=15;$i++)
    
        $numbers[] = mt_rand(1, 20000000);

    
    return $numbers;

?>

【问题讨论】:

我不是 DBA,所以这是评论而非答案,但在 MySQL 和 MongoDB 之间进行选择时,速度不应成为主要考虑因素。诸如无模式与模式(即您的数据模式需要多久更改一次)和规模缩放(即,将数据分片以使典型的读取仅需要来自一台服务器的数据的难易程度)之类的事情对于选择更为重要像这样。 阅读速度怎样才能更快?它从机械设备中读取。与 MySQL 相同。这取决于设备本身的速度,你不能通过代码使用一些奇怪的魔法来突破硬件的限制。 @ImranOmarBukhsh,确实如此。我的观点来自不建议为了改变而改变 - 并提出一种可以利用现有技术提高性能的方法:) 这个问题让我想起了这个:mongodb-is-web-scale.com 人们误以为他们会选择一个或另一个。你的厨房里需要微波炉和烤箱。你不能说我只会使用一个或另一个。两个系统的用例不同。如果您的应用程序的一部分需要 ACID,则使用 RDBMS,如果不关心一致性和约束并且您的实体可以存储为一体(集合),则使用 MongoDB。您最终将使用混合系统,关键是决定将什么存储在哪里。 【参考方案1】:

MongoDB 的速度并不神奇。如果您存储相同的数据,以基本相同的方式组织,并以完全相同的方式访问它,那么您真的不应该期望您的结果会有很大的不同。毕竟,MySQL 和 MongoDB 都是 GPL,所以如果 Mongo 有一些神奇的更好的 IO 代码,那么 MySQL 团队可以将它合并到他们的代码库中。

人们看到真实世界的 MongoDB 性能主要是因为 MongoDB 允许您以更适合您的工作负载的不同方式进行查询。

例如,考虑一个设计,它以规范化的方式保留了有关复杂实体的大量信息。这可以很容易地使用 MySQL(或任何关系数据库)中的数十个表来以正常形式存储数据,并需要许多索引来确保表之间的关系完整性。

现在考虑与文档存储相同的设计。如果所有这些相关表都从属于主表(而且它们通常是),那么您可能能够对数据进行建模,以便将整个实体存储在单个文档中。在 MongoDB 中,您可以将其作为单个文档存储在单个集合中。这就是 MongoDB 开始实现卓越性能的地方。

在 MongoDB 中,要检索整个实体,您必须执行:

对集合进行一次索引查找(假设实体是通过 id 获取的) 检索一个数据库页面的内容(实际的二进制 json 文档)

所以一个 b-tree 查找和一个二进制页面读取。 Log(n) + 1 个 IO。如果索引可以完全驻留在内存中,则 1 IO。

在有 20 个表的 MySQL 中,你必须执行:

在根表上进行一次索引查找(再次假设实体是通过 id 获取的) 使用聚集索引,我们可以假设根行的值在索引中 为实体的 pk 值进行 20 多次范围查找(希望在索引上) 这些可能不是聚集索引,因此一旦我们确定了合适的子行是什么,就会进行 20 多次相同的数据查找。

所以 mysql 的总数,即使假设所有索引都在内存中(这更难,因为它们的数量是它们的 20 倍)大约是 20 次范围查找。

这些范围查找可能由随机 IO 组成——不同的表肯定会驻留在磁盘上的不同位置,并且对于一个实体,同一表中同一范围内的不同行可能不连续(取决于实体已更新等)。

因此,对于本示例,与 MongoDB 相比,MySQL 每次逻辑访问的 IO 大约增加了 20 倍

这就是 MongoDB 在某些用例中提高性能的方式

【讨论】:

如果我们只在mysql中放一个主表呢? @ariso:这是通过非规范化进行的优化。它可以提供性能提升。但是,如果您这样做,那么您将丢弃您的简洁设计,以及关系数据库的所有功能(更不用说大多数功能)。只有在达到列限制之前它才真正起作用。 @SeanReilly 您的实体示例(应使用对象进行编辑,没有面向实体的编程:))无效。就像 ariso 所说,您可以序列化一个对象并将其存储在数据库中,并在需要时反序列化(任何形式的序列化)。持久对象的真正威力在于 oodbms 而不是文档数据库系统。但我同意每个人都有自己的目的和优势(但您的示例更加模糊了该主题的愿景和相关性)。 20 个连接,我想说,这很可能不是最好的数据库架构上的最佳查询。 @SeanReilly 我发现您的示例非常有帮助。您可以为 MySQL 构建一个特殊的接口,该接口自动将对象序列化和反序列化为表,并按照 mongodb 的方式运行。但是,为什么不直接使用专门设计用于这种方式的东西呢?您对“实体”的使用也很有意义。关键是您将数据组织为文档而不是表中的字段。文档是否是用 OO 语言组成的对象与示例无关。【参考方案2】:

您是否有并发,即并发用户?如果你只用一个线程直接运行 1000 次查询,几乎没有区别。这些引擎太容易了:)

但我强烈建议您构建一个真正的负载测试会话,这意味着在同一时间使用 JMeter 等注入器和 10、20 或 50 个用户,这样您就可以真正看到差异(尝试将此代码嵌入到网页JMeter可以查询)。

我今天只是在单个服务器(和一个简单的集合/表)上完成了它,结果非常有趣和令人惊讶(与 MyISAM 引擎和 InnoDb 引擎相比,MongoDb 在写入和读取方面确实更快)。

这确实应该是您测试的一部分:并发和 MySQL 引擎。 然后,数据/模式设计和应用程序需求当然是巨大的需求,超出了响应时间。当你得到结果时告诉我,我也需要这方面的意见!

【讨论】:

你能分享你的结果吗? 是的,结果会很有帮助 当然,这只是规模......如果是苹果对苹果,就像他们在本主题的其余部分所说的那样。因此,如果它在 avg 上执行 x,现在从多个来源进行模拟,请解释为什么 mongo 会更快。即,为了达成协议,让我们说mysql对于单个请求的平均速度更快......为什么mongo现在对于多个请求会变得更快?我觉得这不是很科学。我说测试是有效的.. 但如果您像本主题的其余部分解释的那样将苹果与苹果进行比较,则不太确定差异会有多大。【参考方案3】:

在单服务器上,MongoDb 在读取和写入方面都不会比 mysql MyISAM 快,给定 table/doc 大小为 1 GB 到 20 GB。 MonoDB 在多节点集群上的 Parallel Reduce 上会更快,而 Mysql 无法水平扩展。

【讨论】:

你能提供一些证据或更多细节来支持吗? 无法水平缩放?新开发银行呢? DRBD 支持 MySQL? 这不是真的。 MongoDB 有 16MD 文档限制。如果你喜欢,Mysql 可以拥有更多功能【参考方案4】:

伙计,答案是您基本上是在测试 PHP 而不是数据库。

无论是否注释掉打印结果,都不要费心迭代结果。有很多时间。

   foreach ($cursor as $obj)
    
        //echo $obj["thread_title"] . "<br><Br>";
    

而另一部分则在花费大量的兰特数字。

function get_15_random_numbers()

    $numbers = array();
    for($i=1;$i<=15;$i++)
    
        $numbers[] = mt_rand(1, 20000000) ;

    
    return $numbers;

然后有一个主要的区别b / w implode和in。

最后是这里发生了什么。看起来每次都创建一个连接,因此它测试连接时间加上查询时间。

$m = new Mongo();

对比

$db = new AQLDatabase();

因此,对于去除爵士乐的基础查询,您的 101% 速度可能会提高 1000%。

呃。

【讨论】:

自然,编码实践可以在任何情况下产生很大的不同,但这并不特定于任何类型的语言、api 或扩展。在启动计时器之前生成随机数会有所不同,但进程内的大部分时间无疑来自数据库事务。随机数生成很简单,SQL 和 NoSQL 数据库则不然。 不要选择兰特号码。显然,您每次都错过了创建连接。所有问题加起来都是为了测试超出预期的东西。 不,没有错过。除非调用 mysqli_close(),否则 MySQL 在脚本完成之前不会关闭连接。否则,重复调用 mysqli_connect() 只会从当前资源表中拉出现有的 mysql 资源,而不是提交新的连接过程。我不确定 AQLDatabase 对象是什么,但如果它使用 mysql lib(它可能会这样做),它将具有相同的行为。 MongoDB 扩展使用连接池,因此在脚本中多次创建 mongodb“连接”时会发生相同的基本情况。 我同意他的基准测试可以采用不同的方法,但它反映的基本结果与我见过的其他 MySQL 与 Mongo 基准测试相同。 Mongo 在插入时通常更快(对于更简单的插入要快得多),而 MySQL 在选择时通常更快。 诚然,我太粗暴了;正是“”的 html 字符串 concat 真正“催促”了我。您不需要在测试中进行漂亮的打印。甚至迭代它似乎是一个 php 测试,而不是一个数据库测试。总的来说,AQLDatabase '可能/也许'的时刻......更多的成分意味着更多的未知数。【参考方案5】:

来源:https://github.com/webcaetano/mongo-mysql

10 行

mysql insert: 1702ms
mysql select: 11ms

mongo insert: 47ms
mongo select: 12ms

100 行

mysql insert: 8171ms
mysql select: 10ms

mongo insert: 167ms
mongo select: 60ms

1000 行

mysql insert: 94813ms (1.58 minutes)
mysql select: 13ms

mongo insert: 1013ms
mongo select: 677ms

10000 行

mysql insert: 924695ms (15.41 minutes)
mysql select: 144ms

mongo insert: 9956ms (9.95 seconds)
mongo select: 4539ms (4.539 seconds)

【讨论】:

15 分钟插入 10,000 行?那是一个非常贫乏的 MySQL 数据库。根据我的经验,如果这样的操作持续时间接近 1 秒,我的手机就会亮起抱怨。 :) 几点: 1)Mysql需要优化配置好,大数据的插入方式有很多种,如果做的好的话,15min可以占0.1%,见this page 例如。 2) MongoDB 不会立即将数据写入磁盘,这就是它“看起来”更快的原因,但如果您的计算机崩溃,数据就会丢失。 3) MySQL 读取速度更快 10.000 行需要 15 分钟?你输入每一行? =)))) 对于 10,000 行 - 删除索引、插入、重新索引 任何相信在 mysql 中插入 10 行需要 1.7 秒的说法的人都应该受到 mongo 的痛苦【参考方案6】:

https://github.com/reoxey/benchmark

基准测试

GOLANG1.6 和 PHP5 中 MySQL 和 MongoDB 的速度比较

用于基准测试的系统:DELL cpu i5 4th gen 1.70Ghz * 4 ram 4GB GPU ram 2GB

RDBMS 与 NoSQL 执行不同行数 10,100,1000,10000,100000,1000000 的 INSERT、SELECT、UPDATE、DELETE 速度比较

用来执行的语言是:PHP5 & Google最快的语言GO 1.6

________________________________________________
GOLANG with MySQL (engine = MyISAM)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            INSERT
------------------------------------------------
num of rows             time taken
------------------------------------------------
10                      1.195444ms
100                     6.075053ms
1000                    47.439699ms
10000                   483.999809ms
100000                  4.707089053s
1000000                 49.067407174s


            SELECT
------------------------------------------------
num of rows             time taken
------------------------------------------------
1000000                 872.709µs


        SELECT & DISPLAY
------------------------------------------------
num of rows             time taken
------------------------------------------------
1000000                 20.717354746s


            UPDATE
------------------------------------------------
num of rows             time taken
------------------------------------------------
1000000                 2.309209968s
100000                  257.411502ms
10000                   26.73954ms
1000                    3.483926ms
100                     915.17µs
10                      650.166µs


            DELETE
------------------------------------------------
num of rows             time taken
------------------------------------------------
1000000                 6.065949ms
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


________________________________________________
GOLANG with MongoDB
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            INSERT
------------------------------------------------
num of rows             time taken
------------------------------------------------
10                      2.067094ms
100                     8.841597ms
1000                    106.491732ms
10000                   998.225023ms
100000                  8.98172825s
1000000                 1m 29.63203158s


            SELECT
------------------------------------------------
num of rows             time taken
------------------------------------------------
1000000                 5.251337439s


        FIND & DISPLAY (with index declared)
------------------------------------------------
num of rows             time taken
------------------------------------------------
1000000                 21.540603252s


            UPDATE
------------------------------------------------
num of rows             time taken
------------------------------------------------
1                       1.330954ms
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

________________________________________________
PHP5 with MySQL (engine = MyISAM)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            INSERT
------------------------------------------------
num of rows             time taken
------------------------------------------------
 10                     0.0040680000000001s
 100                    0.011595s
 1000                   0.049718s
 10000                  0.457164s
 100000                 4s
 1000000                42s


            SELECT
------------------------------------------------
num of rows             time taken
------------------------------------------------
 1000000                <1s


            SELECT & DISPLAY
------------------------------------------------
num of rows             time taken
------------------------------------------------
  1000000               20s
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

________________________________________________
PHP5 with MongoDB 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            INSERT
------------------------------------------------
num of rows             time taken
------------------------------------------------
10                      0.065744s
100                     0.190966s
1000                    0.2163s
10000                   1s
100000                  8s
1000000                 78s


            FIND
------------------------------------------------
num of rows             time taken
------------------------------------------------
1000000                 <1s


            FIND & DISPLAY
------------------------------------------------
num of rows             time taken
------------------------------------------------
1000000                 7s


            UPDATE
------------------------------------------------
num of rows             time taken
------------------------------------------------
1000000                 9s

【讨论】:

myisam不是innodb,还有哪个mongodb版本和存储引擎? 指定 MySQL 和 MongoDB 版本很重要。 不要使用 MyISAM。一定要使用批量插入! MySQL 在 Insert 查询中比 Mongodb 快?!在 mysql 需要准备列和关系之前,这似乎不是真的。 mysql select比mongodb select快,但是在insert查询中,mongo更快【参考方案7】:

这里是a little research,它使用 MySQL 和 Mongo 探索了 RDBMS 和 NoSQL,结论与@Sean Reilly 的回复一致。简而言之,好处来自设计,而不是一些原始的速度差异。第 35-36 页的结论:

RDBMS 与 NoSQL:性能和扩展比较

项目测试、分析和比较了性能和 两种数据库类型的可扩展性。所做的实验包括 运行不同数量和类型的查询,有些比 其他人,以分析数据库如何随着增加而扩展 加载。在这种情况下,最重要的因素是使用的查询类型 因为 MongoDB 可以更快地处理更复杂的查询,这主要是因为它 以牺牲数据重复为代价的更简单的模式意味着 NoSQL 数据库可能包含大量数据重复。虽然 可以使用直接从 RDBMS 迁移的模式 消除了MongoDB底层数据表示的优势 允许对 数据库作为表被合并。 尽管性能提升 MongoDB 在这些复杂的查询中已经超过 MySQL,当基准 对 MySQL 查询进行建模,类似于 MongoDB 复杂查询 使用嵌套的 SELECTs MySQL 表现最好,尽管数量较多 的连接,两者的行为相似。 最后一种查询 基准测试是包含两个 JOINS 和一个的复杂查询 子查询显示了 MongoDB 相对于 MySQL 的优势,因为它使用 子文档。这种优势是以数据重复为代价的 这会导致数据库大小的增加。如果这样的查询是 在应用程序中很典型,那么考虑 NoSQL 很重要 数据库作为替代方案 考虑较大的存储成本和内存大小 数据库大小。

【讨论】:

【参考方案8】:

老实说,即使 MongoDB 速度较慢,Mon​​goDB 也绝对让我和你的代码更快......无需担心愚蠢的表列、行或实体迁移......

使用 MongoDB,您只需实例化一个类并保存!

【讨论】:

不同意,你必须选择最合适的技术,而不是最容易编码的。因为您可以将所有内容保存到文本文件中,然后根本无需担心数据库:) 不同意。这是一个不费吹灰之力的举动。 MongoDB 不能执行事务,而 MySQL 可以。这为我节省了很多编码,其中在 mongo 中,我必须在应用程序上编写一个功能块来执行它。所以你真的需要非常仔细地考虑每个系统的设计。两者各有利弊。 关于更快的编码也有争议,这是主观的。有些人更喜欢 ORM 和微 ORM,以自动管理模型更改和/或迁移,这导致开发人员只在一个地方(数据库)管理模式,就像在应用层中管理模式一样。跨度>

以上是关于MySQL 与 MongoDB 1000 次读取的主要内容,如果未能解决你的问题,请参考以下文章

易于扩展 mongodb 与 mysql

Spring Reactive with MongoDB 失败超过 1000 条记录

使用php读取/写入负载平衡-mongodb vs mysql [关闭]

MongoDB与MySQL有区别吗?用一个表格跟你说明

与 ReentrantLock 相比,ReentrantReadWriteLock 的性能非常差

MongoDB环境搭建与初始配置