我对MongoDb非常兴奋,最近一直在测试它。我在MySQL中有一个叫posts的表,大约有2000万条记录,索引只在一个名为“id”的字段上。
我想与MongoDB比较速度,我运行了一个测试,从我们巨大的数据库中随机获取并打印15条记录。我为mysql和MongoDB分别运行了大约1000次查询,我很惊讶我没有注意到速度上有很大的差异。也许MongoDB快1.1倍。这太令人失望了。我做错什么了吗?我知道我的测试并不完美,但当涉及到读取密集的杂务时,MySQL与MongoDb不相上下。
注意:
我有双核+(2线程)i7 cpu和4GB ram
我在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;
}
?>
MongoDB并不是神奇地更快。如果您存储相同的数据,以基本相同的方式组织,并以完全相同的方式访问它,那么您真的不应该期望您的结果有很大的不同。毕竟,MySQL和MongoDB都是GPL,所以如果MongoDB有一些神奇的更好的IO代码,那么MySQL团队就可以把它合并到他们的代码库中。
人们看到真实世界的MongoDB性能很大程度上是因为MongoDB允许您以一种对您的工作负载更敏感的不同方式进行查询。
例如,考虑一个设计,它以规范化的方式保存了关于一个复杂实体的大量信息。这可以很容易地使用MySQL(或任何关系db)中的数十个表来以正常形式存储数据,需要许多索引来确保表之间的关系完整性。
现在考虑相同的文档存储设计。如果所有这些相关的表都从属于主表(通常是这样),那么您就可以对数据进行建模,使整个实体存储在单个文档中。在MongoDB中,您可以将其存储为单个文档,在单个集合中。这就是MongoDB开始实现卓越性能的地方。
在MongoDB中,要检索整个实体,你必须执行:
对集合进行一次索引查找(假设实体是通过id获取的)
检索一个数据库页面的内容(实际的二进制json文档)
b-树查找,二叉页读取。Log(n) + 1个IOs。如果索引可以完全驻留在内存中,则为1 IO。
在有20个表的MySQL中,你必须执行:
根表上的一次索引查找(同样,假设实体是通过id获取的)
对于聚集索引,我们可以假设根行的值在索引中
对实体的pk值进行20+范围查找(希望是在索引上)
这些可能不是聚集索引,因此一旦我们确定了适当的子行是什么,就需要进行相同的20+数据查找。
所以对于mysql,即使假设所有索引都在内存中(这很难,因为索引的数量是内存的20倍),也需要大约20次范围查找。
这些范围查找很可能由随机IO组成——不同的表肯定位于磁盘上的不同位置,对于同一个实体,同一表中相同范围中的不同行可能不是连续的(取决于实体是如何更新的,等等)。
因此,对于这个例子,与MongoDB相比,MySQL的每次逻辑访问的IO数量是MongoDB的20倍。
这就是MongoDB在某些用例中提高性能的原因。
答案是你基本上是在测试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内爆和在。
最后是这里发生了什么。看起来像是每次都创建一个连接,因此它测试连接时间加上查询时间。
$m = new Mongo();
vs
$db = new AQLDatabase();
因此,对于去除jazz的底层查询,您的101%的速度可能会提高1000%。
呃。
https://github.com/reoxey/benchmark
基准
MySQL和MongoDB在GOLANG1.6和PHP5中的速度比较
用于基准测试的系统:DELL cpu i5第四代1.70Ghz * 4 ram 4GB GPU ram 2GB
RDBMS与NoSQL的INSERT, SELECT, UPDATE, DELETE执行不同数量的行10,100,1000,10000,100000,1000000的速度比较
用于执行的语言是:PHP5 &谷歌最快的语言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
MongoDB并不是神奇地更快。如果您存储相同的数据,以基本相同的方式组织,并以完全相同的方式访问它,那么您真的不应该期望您的结果有很大的不同。毕竟,MySQL和MongoDB都是GPL,所以如果MongoDB有一些神奇的更好的IO代码,那么MySQL团队就可以把它合并到他们的代码库中。
人们看到真实世界的MongoDB性能很大程度上是因为MongoDB允许您以一种对您的工作负载更敏感的不同方式进行查询。
例如,考虑一个设计,它以规范化的方式保存了关于一个复杂实体的大量信息。这可以很容易地使用MySQL(或任何关系db)中的数十个表来以正常形式存储数据,需要许多索引来确保表之间的关系完整性。
现在考虑相同的文档存储设计。如果所有这些相关的表都从属于主表(通常是这样),那么您就可以对数据进行建模,使整个实体存储在单个文档中。在MongoDB中,您可以将其存储为单个文档,在单个集合中。这就是MongoDB开始实现卓越性能的地方。
在MongoDB中,要检索整个实体,你必须执行:
对集合进行一次索引查找(假设实体是通过id获取的)
检索一个数据库页面的内容(实际的二进制json文档)
b-树查找,二叉页读取。Log(n) + 1个IOs。如果索引可以完全驻留在内存中,则为1 IO。
在有20个表的MySQL中,你必须执行:
根表上的一次索引查找(同样,假设实体是通过id获取的)
对于聚集索引,我们可以假设根行的值在索引中
对实体的pk值进行20+范围查找(希望是在索引上)
这些可能不是聚集索引,因此一旦我们确定了适当的子行是什么,就需要进行相同的20+数据查找。
所以对于mysql,即使假设所有索引都在内存中(这很难,因为索引的数量是内存的20倍),也需要大约20次范围查找。
这些范围查找很可能由随机IO组成——不同的表肯定位于磁盘上的不同位置,对于同一个实体,同一表中相同范围中的不同行可能不是连续的(取决于实体是如何更新的,等等)。
因此,对于这个例子,与MongoDB相比,MySQL的每次逻辑访问的IO数量是MongoDB的20倍。
这就是MongoDB在某些用例中提高性能的原因。