MySQLでHDD/SSDのアクセススピードを比較する

SSDにするとBlukcopyは5倍ぐらい早くなる – Moonmile Solutions Blog の比較として、MySQL では、SSD/HDD はどうなんだろうね?という話です。MySQL の Connector には Bulkcopy っぽいものがないので、ちまちまと insert しています。なので、その分遅くなるので、適当に1000件単位でトランザクション使って commit します。1件ずつ insert するよりは早いのですが、SQL Server よりは SSD 比で 10 倍ぐらい、HDD 比で 2 倍ぐらい遅いです。SSD/HDD で倍数に差がでているのは、SQL Server + SSD がむちゃくちゃ早いからですね。

追記 MySqlBulkLoader というものがあるそうなので、後で試します。

imageimage

imageimage

SSD で 65.3秒、HDD で 74.2秒。

SSD HDD
SQL Server 7.8 sec 32.1 sec
MySQL 65.3 sec 74.2 sec

ってことで、SQL Server は bulkcopy, MySQL はトランザクション使ったinsert文なので、相互には比較できませんが(今度 SQL Server のほうを insert 文に変えて実験しましょう)、SSDとHDDの比較で言えば、SQL Server のほうが断然効果的…という結論ではなくて、MySQL が SSD の書き込みスピードに追い付いていないってのが遅い原因です。

書き込み速度 SSD HDD
SQL Server 132 MB/sec 35.1 MB/sec
MySQL 11.0 MB/sec 約7 MB/sec

になるので、SQL Server の HDD 書き込みよりも遅いスピードで SSD に書きにいっちゃってます。この要因は、プログラム側にもあって、

  • MySQLにバルクコピーがないので、ちまちま insert してる。
  • たぶん、DataTable から CommandParamter に移す時にスピードが遅くなってる。

てな感じでしょうか。でも、まあ、100万件のアクセス生ログを 1分弱で insert できるのは結構よいかなと。以前、mysqldump したのだと30分位かかって気がします(以前とは、メモリもCPUも違うので単純比較はできませんが)。

MySQL のデータファイルを HDD/SSD に振り分ける方法は、漢(オトコ)のコンピュータ道: InnoDBのファイルサイズ管理 にある、innodb_file_per_table の設定と、シンボリックリンク(mklink)を使っています。この方法は別のエントリにまとめます。

以下は、insert 文のところの抜粋です。参考にでも。

async Task GoBlukCopy(string CNSTR)
{
    MySqlConnection cn = new MySqlConnection(CNSTR);
    MySqlCommand cmd = new MySqlCommand("INSERT INTO logs  values ( @dt, @code, @ip, @req, @url )", cn );
    cmd.Parameters.Add(  new MySqlParameter("@dt",  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter("@code",  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter("@ip",  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter("@req",  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter("@url",  MySqlDbType.String ));

    DateTime start = DateTime.Now;

    _completed = false;
    _count = 0;
    await Task.Factory.StartNew(
        () =>
        {
            cn.Open();

            // 1000件ごとにcommit する
            MySqlTransaction tr = cn.BeginTransaction();
            foreach (DataRow row in _dt.Rows)
            {
                cmd.Parameters["@dt"].Value = row["dt"];
                cmd.Parameters["@code"].Value = row["code"];
                cmd.Parameters["@ip"].Value = row["ip"];
                cmd.Parameters["@req"].Value = row["req"];
                cmd.Parameters["@url"].Value = row["url"];
                cmd.ExecuteNonQuery();
                _count++;
                if (_count % 1000 == 0)
                {
                    tr.Commit();
                    tr = cn.BeginTransaction();
                }
            }
            tr.Commit();
            cn.Clone();
            _completed = true;
        });
}
カテゴリー: MySQL, パフォーマンス パーマリンク