せっかく、最強.NET開発PCにSSDを入れたので、SQL Serverがどれくらい早くなるか計測してみます。つーか、もともとその目的もあって、SSD にしています。大容量の SSD はそれなりにお高いので、本当なら 64GB ぐらいの安めのを買って試してみたいところなのですが、まだ買ってないので。
PLEXTRO PX-512M5P
http://www.goplextor.com/jp/index.php/m5-pro
WDC WD20EZRX-00DC0B0 1TB
という WD にあまりに不利な状況なのですが…まあ、ひと昔前の HDD と最新の SSD を比較するということでやってみます。状況としては、昔の HDD に SQL Server をがりがりやってチューニングして頑張って、という状況だけど、最近データアクセスが遅くて困る。となると、もっとチューニングをするのか、CPU を変えるのか、ソフトウェアをリプレースするのか?と色々考えるけども、HDD から SSD にデータベースを乗せ換えるだけでも十分じゃない?ってところです。
以下、100万件のWEBアクセスログを、BulkCopy でインサートして計測しています。100万件とは言いますが、実は大したことがなくて、実際に業務で扱うデータは1億件ぐらいと桁が2桁ぐらい違いますよね。以前は、この100万件扱うのにひいこら言っていたはずなんですが、CPU とメモリの関係なのか、結構スムースに動きます。なので、相対値としてみてください。
SSD にバルクインサート中

100万件インサートで 7.8秒

HDD にバルクインサート中

100万件インサートで 32.1秒
実測値で5倍ぐらいの違いが出ます。これは、大量のデータインサートなので、状況が特別なのですが、書き込みの場合でも SSD のほうが遥かに早い。
で、別途読み込み(SELECT)をやってみたのですが、こっちのほうはディスクキャッシュが効いていると、どちらも .3 秒とかで返ってくるので比較になりません。当然、インデックスがない状態でこれですから。SELECT のほうは、別途計測方法を考えてリトライしましょう。
■実験ソース
void GoBlukCopy(string CNSTR)
{
DataTable dt = _dt;
SqlConnection cn = new SqlConnection(CNSTR);
SqlBulkCopy bc = new SqlBulkCopy(cn);
DateTime start = DateTime.Now;
bc.BulkCopyTimeout = 0;
bc.DestinationTableName = "logs";
cn.Open();
bc.WriteToServer(dt);
cn.Close();
DateTime end = DateTime.Now;
label2.Text = string.Format("BulkCopy完了 {0:#.0} sec",
((TimeSpan)(end - start)).TotalSeconds);
}
ついでにアクセスログから DataTable を作るところも。非同期を使っているので、別の記事にでも解説を。
DataTable _dt;
int _count;
bool _completed;
/// <summary>
/// ファイルから読み込み
/// </summary>
/// <returns></returns>
public async Task<DataTable> MakeDataTable()
{
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("dt", typeof(string)));
dt.Columns.Add(new DataColumn("code", typeof(string)));
dt.Columns.Add(new DataColumn("ip", typeof(string)));
dt.Columns.Add(new DataColumn("req", typeof(string)));
dt.Columns.Add(new DataColumn("url", typeof(string)));
_completed = false;
await Task.Factory.StartNew(
() =>
{
var sr = System.IO.File.OpenText(@"D:sitelogsout3.csv");
_count = 0;
while (sr.EndOfStream == false)
{
string line = sr.ReadLine();
string[] v = line.Split(new string[] { "t" }, StringSplitOptions.None);
DataRow row = dt.NewRow();
dt.Rows.Add(row);
row["dt"] = v[0];
row["code"] = v[1];
row["ip"] = v[2];
row["req"] = v[3];
row["url"] = v[4];
_count++;
}
sr.Close();
_completed = true;
_dt = dt;
});
return dt;
}
private void button2_Click(object sender, EventArgs e)
{
Task t1 = MakeDataTable();
Task t2 = Task.Factory.StartNew(async () =>
{
while (_completed == false)
{
await Task.Delay(500);
label2.Invoke((MethodInvoker)(() => label2.Text =
string.Format("{0} 件読み込み中", _count)));
}
label2.Invoke((MethodInvoker)(() => label2.Text =
string.Format("{0} 件読み込み完了", _count)));
});
}

