私は MongoDb にとても興味があり、最近テストしています。MySQL に posts というテーブルがあり、そこには 'id' というフィールドのみでインデックスが付けられた約 2,000 万件のレコードがありました。
MongoDB との速度を比較したかったので、巨大なデータベースからランダムに 15 件のレコードを取得して印刷するテストを実行しました。mysql と MongoDB でそれぞれ約 1,000 回クエリを実行しましたが、速度に大きな違いが見られなかったことに驚きました。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;
}
?>
ベストアンサー1
MongoDB は魔法のように高速ではありません。基本的に同じ方法で整理された同じデータを保存し、まったく同じ方法でアクセスする場合、結果が大きく異なることは期待できません。結局のところ、MySQL と MongoDB はどちらも GPL なので、Mongo に魔法のように優れた IO コードが含まれていれば、MySQL チームはそれをコードベースに組み込むだけで済みます。
MongoDB では、ワークロードに適した異なる方法でクエリを実行できるため、実際の MongoDB のパフォーマンスを実感できます。
たとえば、複雑なエンティティに関する大量の情報を正規化された形式で保存する設計を考えてみましょう。この場合、MySQL (または任意のリレーショナル データベース) の数十のテーブルを使用してデータを正規形式で保存することになり、テーブル間のリレーショナル整合性を確保するために多数のインデックスが必要になります。
次に、ドキュメント ストアを使用した同じ設計について考えてみましょう。関連するテーブルがすべてメイン テーブルに従属している場合 (多くの場合そうなります)、エンティティ全体を 1 つのドキュメントに格納するようにデータをモデル化できる可能性があります。MongoDB では、これを 1 つのドキュメントとして、1 つのコレクションに格納できます。ここから MongoDB は優れたパフォーマンスを実現します。
MongoDB では、エンティティ全体を取得するには、以下を実行する必要があります。
- コレクション上の 1 つのインデックス検索 (エンティティが ID によって取得されると仮定)
- 1 つのデータベース ページ (実際のバイナリ JSON ドキュメント) の内容を取得します。
つまり、B ツリー検索とバイナリ ページの読み取りです。Log(n) + 1 IO。インデックス全体をメモリ内に配置できる場合は、1 IO です。
20 個のテーブルを持つ MySQL では、次の操作を実行する必要があります。
- ルート テーブル上の 1 つのインデックス検索 (ここでも、エンティティは ID によって取得されると仮定)
- クラスター化インデックスでは、ルート行の値がインデックス内にあると想定できます。
- エンティティの pk 値に対する 20 以上の範囲検索 (できればインデックス上)
- これらはおそらくクラスター化インデックスではないため、適切な子行が判明したら、同じ 20 回以上のデータ検索が行われます。
したがって、すべてのインデックスがメモリ内にあると仮定しても (インデックスの数が 20 倍多いため、これは困難です)、mysql の合計は約 20 回の範囲検索になります。
これらの範囲検索はランダム IO で構成される可能性が高く、異なるテーブルはディスク上の異なる場所に確実に存在し、エンティティの同じテーブル内の同じ範囲内の異なる行が連続していない可能性があります (エンティティの更新方法などによって異なります)。
したがって、この例では、最終的な合計は、MongoDB と比較して、MySQL の論理アクセスあたりの IO が約20 倍になります。
これは、MongoDB がいくつかのユースケースでパフォーマンスを向上させる方法です。