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 というものがあるそうなので、後で試します。
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; }); }