[解決済み] MySQLとMongoDBの比較 1000回読み込み
質問
私はMongoDbにとても期待していて、最近テストしています。MySQLにpostsというテーブルがあって、約2000万件のレコードがあり、'id'というフィールドにのみインデックスが付けられています。
MongoDBと速度を比較したいと思い、巨大なデータベースからランダムに15レコードを取得して印刷するテストを実行しました。mysqlとMongoDBでそれぞれ1,000回ずつクエリを実行しましたが、スピードに大きな差がないことに驚いています。もしかしたら、MongoDBの方が1.1倍速いかもしれません。それはとても残念なことです。私が何か間違っているのでしょうか?私のテストが完璧でないことは分かっていますが、読み込みに集中する作業に関しては、MySQLはMongoDbと同等なのでしょうか?
注意してください。
- デュアルコア+(2スレッド)i7 cpuと4GB RAMを搭載しています。
- MySQLに100万レコードのパーティションが20個あります。
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なので、もしMongoが魔法のように優れたIOコードを持っていたら、MySQLチームはそれをコードベースに取り込めばいいだけなのです。
MongoDBが現実の世界でパフォーマンスを発揮しているのは、MongoDBがワークロードに適した別の方法でクエリーを実行できるようにしたことが大きいです。
例えば、複雑なエンティティに関する多くの情報を正規化した形で保存するデザインを考えてみましょう。この場合、MySQL(または他のリレーショナルデータベース)の何十ものテーブルを使用して、データを正規の形で保存し、テーブル間の関係整合性を確保するために多くのインデックスを使用することが容易にできます。
次に、同じ設計をドキュメントストアで考えてみましょう。関連するすべてのテーブルがメインテーブルの下位にある場合(多くの場合そうです)、エンティティ全体を1つのドキュメントに格納するようにデータをモデル化することができるかもしれません。MongoDBでは、これをひとつのドキュメントとして、ひとつのコレクションに格納できます。MongoDBはここから優れたパフォーマンスを発揮するのです。
MongoDBでは、エンティティ全体を取得するためには、以下のようなパフォーマンスが必要です。
- コレクションのインデックス検索 (エンティティは id で取得されると仮定)
- データベース1ページの内容を取得する(実際のバイナリjsonドキュメント)。
つまり、B-treeのルックアップと、バイナリページの読み込みです。Log(n) + 1 IOです。もしインデックスが完全にメモリに存在できるなら、1IO。
20のテーブルを持つMySQLでは、実行しなければならない。
- ルートテーブルのインデックス検索を1回(ここでも、エンティティはidで取得されると仮定しています)
- クラスタ化されたインデックスでは、ルート行の値がインデックスにあると仮定することができる
- エンティティのpk値について、(できればインデックスで)20以上の範囲検索を行う。
- これらはおそらくクラスタ化されたインデックスではないので、適切な子行が何であるかを把握した後は、同じように20以上のデータ検索を行います。
つまり、mysqlの場合、すべてのインデックスがメモリ上にあると仮定しても(20倍もあるので大変ですが)、合計で約20回の範囲ルックアップが必要なのです。
これらの範囲検索は、おそらくランダムIOで構成されています。異なるテーブルは間違いなくディスク上の異なる場所に存在し、同じテーブルの同じ範囲内の異なる行は(エンティティの更新方法などに応じて)連続していない可能性があります。
つまり、この例の場合、最終的な集計は約 20回 論理アクセスあたりの IO は、MySQL の方が MongoDB よりも多くなっています。
MongoDBはこうしてパフォーマンスを向上させる いくつかのユースケースで .
関連
-
MySqlの整数インデックスと文字列インデックスの失敗または暗黙の変換問題
-
[解決済み] MySQLでdatetimeとtimestampのどちらのデータ型を使用すべきですか?
-
[解決済み] MySQLでコマンドラインを使用してSQLファイルをインポートするにはどうすればよいですか?
-
[解決済み] MongoDBに "like "を使ってクエリを実行する方法
-
[解決済み] MySQLのAUTO_INCREMENTをリセットする方法
-
[解決済み] MySQLの複数行を1つのフィールドに連結することはできますか?
-
[解決済み] MySQLのクエリ結果をCSV形式で出力するにはどうすればよいですか?
-
[解決済み] ブーリアン値を格納するために使用するMySQLデータ型
-
[解決済み] コマンドラインからMongoDBデータベースを削除する方法を教えてください。
-
[解決済み] MongoDBとその逆の上にCouchDBを使用するとき
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
MySQLにおけるorder byの使用方法の詳細
-
MySQLのLike演算子に関する詳細
-
mysqlのデータ圧縮性能比較 詳細
-
MySQL インタビューの質問 - ハッシュインデックスを設定する方法
-
MysqlからElasticsearchにデータを同期させる方法を説明します。
-
MySQLで正規表現を使う 詳細
-
[解決済み] datetimeの挿入時に文字列から日付や時刻を変換すると、変換に失敗する
-
[解決済み】DynamoDB : 提供されたキー要素がスキーマと一致しません。
-
[解決済み] MySQLのプロセスリストを見つけ、それらのプロセスを終了させる方法は?
-
[解決済み] Ubuntu linux上で動作するリモートMySQLサーバーを再起動する方法は?