我对MongoDb非常兴奋,最近一直在测试它.我在MySQL中有一个名为posts的表,其中大约有2000万条记录只在一个名为"id"的字段上被索引.

我想将速度与MongoDB进行比较,并运行了一个测试,从我们庞大的数据库中随机获取并打印15条记录.我为mysql和MongoDB分别运行了大约1000次查询,我很惊讶我没有注意到速度上有很大的差异.也许MongoDB的速度快了1.1倍.这太令人失望了.我做错什么了吗?我知道我的测试不是完美的,但是MySQL与MunGDB相当.


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

Sample Code Used For Testing 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;
}

?>


Sample Code For Testing 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;
}
?>

推荐答案

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

人们看到真实世界中MongoDB的性能很大程度上是因为MongoDB允许您以一种对您的工作负载更敏感的方式进行查询.

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

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

在MongoDB中,要检索整个实体,必须执行以下操作:

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

因此,b-树查找和二进制页面读取.日志(log)(n)+1个IOs.如果索引可以完全驻留在内存中,则为1 IO.

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

  • 根表上的一个索引查找(同样,假设实体是通过id获取的)
  • 对于聚集索引,我们可以假设根行的值在索引中
  • 实体pk值的20多个范围查找(希望是在索引上)
  • 这些可能不是聚集索引,因此,一旦我们弄清楚合适的子行是什么,就会进行相同的20多个数据查找.

因此,即使假设所有索引都在内存中(因为索引的数量是内存的20倍,所以更难),mysql的总查找量也大约是20个范围查找.

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

所以在这个例子中,与MongoDB相比,使用MySQL进行每个逻辑访问的最终统计结果是大约多了20 times个IO.

这就是MongoDB将性能提升in some use cases的方式.

Mysql相关问答推荐

基于多行从表中 Select

JPA对具有动态键和动态值的JSON列的原生查询

为什么MySQL派生条件下推优化不起作用

Mysql:使用like Select 查询

获取最大登录应用程序用户数以及何时

模拟Mysql Cursor类的fetchone()方法,并将其返回值设置为None

关于设置为 NOT NULL 时的 CHAR 默认值

如何将数据导入MySQL中的master/replica struct

Mysql JSON_REMOVE 数组键和值 (MariaDB)

相关查询 - 在派生表中,我可以有多个嵌套级别吗?

如何在更新语句中使用多个子字符串函数?

总行大小不超过 65535,但我得到行大小太大.所用表类型的最大行大小,不包括 BLOB,是 65535错误

按 SQL 删除分组前的重复项

MYSQL如何将虚拟列添加到现有表中

在 MySQL 中 Select COUNT of MAX

如何判断嵌套查询返回的元组中的每个条目是否相同?

如何在 MySQL 中删除具有 2 列作为复合主键的多行?

PHP PDO 与普通 mysql_connect

如何删除没有临时表的 MySQL 表中的所有重复记录

MySQL 删除多列