대용량 Datatable(즉 Rows가 많은) 을 SQL Server에 Insert할 때 속도에 유의할 필요가 있습니다.
1. 우선 제가 기존에 쓰던방식 - 하나씩 insert하기
const string sql = "INSERT INTO [Test] ([Value]) Values (@Value)";
for (var i = 0; i < count; i++)
{
connection.Execute(sql, new { Value = Guid.NewGuid().ToString()});
}
저의 환경에서 10,000 rows insert할 때 54,533ms의 시간이 걸렸습니다. 1초당 약 183 레코드를 저장한다고 생각하시면 됩니다.
2. 한번에 1000개씩 insert
foreach (var batch in Enumerable.Range(0, count).Chunk(1000))
{
if (batch.Length == 0) continue;
var sql = "INSERT INTO [Test] ([Value]) VALUES \r\n" + string.Join(",\r\n", batch.Select(x => $"('{Guid.NewGuid().ToString()}')"));
connection.Execute(sql);
}
SQL Server는 여러 레코드를 단일 sql문으로 insert할 수 있도록 지원합니다. 그러니까 1000개를 한번에 insert하는 것이죠.
제 환경에서 100만개의 레코드를 insert하니 22,256ms의 시간이 결렸습니다. 초당 44,931개 수준
3. 더빠른 Bulk Copy
var table = new DataTable();
table.Columns.Add("Value", typeof(string));
for (var i = 0; i < count; i++)
{
table.Rows.Add(Guid.NewGuid().ToString());
}
using (var bulk = new SqlBulkCopy(this.connection))
{
bulk.DestinationTableName = "test";
bulk.WriteToServer(table);
SQL Server 는 bulk insert를 지원하죠 c#에서는 더 쉽게 접근 할 수 있어요.
제 환경에서 100만개의 레코드를 9,315ms에 끝내버립니다. 초당 107,353개 수준인거에요
4. C# Datatable MS SQL로 insert(Bulk copy)
var table = new DataTable();
// read the table structure from the database
using (var adapter = new SqlDataAdapter($"SELECT TOP 0 * FROM test", this.connection))
{
adapter.Fill(table);
};
for (var i = 0; i < count; i++)
{
var row = table.NewRow();
row["Value"] = Guid.NewGuid().ToString();
table.Rows.Add(row);
}
using (var bulk = new SqlBulkCopy(this.connection))
{
bulk.DestinationTableName = "test";
bulk.WriteToServer(table);
}
C#에서 우선 DataTable을 만들고 dst table을 지정합니다. 그러고나서 값을 때려박으면 되요 참 쉽죠?
대충 100~1000row는 그냥 insert해도 될 것 같은데 그 이상이면 한번쯤 고려해보세요