[英]Fastest way to insert 30 thousand rows in a temp table on SQL Server with C#
我試圖找出如何使用c#在SQL Server的臨時表中提高插入性能。 有些人說我應該使用SQLBulkCopy但是我必須做錯了,因為它似乎比簡單地構建一個SQL插入字符串慢得多。
我使用SQLBulkCopy創建表的代碼如下:
public void MakeTable(string tableName, List<string> ids, SqlConnection connection)
{
SqlCommand cmd = new SqlCommand("CREATE TABLE ##" + tableName + " (ID int)", connection);
cmd.ExecuteNonQuery();
DataTable localTempTable = new DataTable(tableName);
DataColumn id = new DataColumn();
id.DataType = System.Type.GetType("System.Int32");
id.ColumnName = "ID";
localTempTable.Columns.Add(id);
foreach (var item in ids)
{
DataRow row = localTempTable.NewRow();
row[0] = item;
localTempTable.Rows.Add(row);
localTempTable.AcceptChanges();
}
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
{
bulkCopy.DestinationTableName = "##" + tableName;
bulkCopy.WriteToServer(localTempTable);
}
}
這樣我的插入需要很長時間才能運行。 我讓插件以另一種方式更快地工作:
我將insert位創建為一個字符串,並在我的SQL create temp table語句中加入它:
創建插入字符串:
public string prepareInserts(string tableName, List<string> ids)
{
List<string> inserts = new List<string>();
var total = ids.Select(p => p).Count();
var size = 1000;
var insert = 1;
var skip = size * (insert - 1);
var canPage = skip < total;
while (canPage)
{
inserts.Add(" insert into ##" + tableName + @" (ID) values " + String.Join(",", ids.Select(p => string.Format("({0})", p))
.Skip(skip)
.Take(size)
.ToArray()));
insert++;
skip = size * (insert - 1);
canPage = skip < total;
}
string joinedInserts = String.Join("\r\n", inserts.ToArray());
return joinedInserts;
}
創建查詢后在SQL語句中使用它們:
inserts = prepareInserts(tableName, ids);
var query = @"IF EXISTS
(
SELECT *
FROM tempdb.dbo.sysobjects
WHERE ID = OBJECT_ID(N'tempdb..##" + tableName + @"')
)
BEGIN
DELETE FROM ##" + tableName + @"
END
ELSE
BEGIN
CREATE TABLE ##" + tableName + @"
(ID int)
END " + inserts;
var command = new SqlCommand(query, sqlConnection);
...
自從我看到有人告訴我(在堆棧交換機上https://dba.stackexchange.com/questions/44217/fastest-way-to-insert-30-thousand-rows-in-sql-server/44222?noredirect= 1#comment78137_44222 )我應該使用SQLBulkCopy,這會更快我相信我應該改進我的方式。 因此,如果有人可以建議我如何改進我的SQLBulkCopy代碼或告訴我是否有更好的插入語句可以提高我的應用程序的性能,這將是偉大的。
你的問題可能在localTempTable.AcceptChanges();
因為它提交了您的更改。
如果你做下一個,我認為它會運行得更快
foreach (var item in ids)
{
DataRow row = localTempTable.NewRow();
row[0] = item;
localTempTable.Rows.Add(row);
}
localTempTable.AcceptChanges();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
{
bulkCopy.DestinationTableName = "##" + tableName;
bulkCopy.WriteToServer(localTempTable);
}
提交自加載或自上次調用AcceptChanges以來對此DataSet所做的所有更改。
我自己使用StopWatch對象運行此代碼來測量時間。 這是每次迭代中的AcceptChanges變得緩慢。
public void MakeTable(string tableName, List<string> ids, SqlConnection connection)
{
SqlCommand cmd = new SqlCommand("CREATE TABLE ##" + tableName + " (ID int)", connection);
cmd.ExecuteNonQuery();
DataTable localTempTable = new DataTable(tableName);
DataColumn id = new DataColumn();
id.DataType = System.Type.GetType("System.Int32");
id.ColumnName = "ID";
localTempTable.Columns.Add(id);
System.Diagnostics.Stopwatch sw1 = new System.Diagnostics.Stopwatch();
sw1.Start();
foreach (var item in ids)
{
DataRow row = localTempTable.NewRow();
row[0] = item;
localTempTable.Rows.Add(row);
}
localTempTable.AcceptChanges();
long temp1 = sw1.ElapsedMilliseconds;
sw1.Reset();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
{
bulkCopy.DestinationTableName = "##" + tableName;
bulkCopy.WriteToServer(localTempTable);
}
long temp2 = sw1.ElapsedMilliseconds;
}
當AccpetChanges在foreach循環中時的結果
當它不是
差異是3個數量級:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.