我有一个工具,每小时在数据库中插入/更新数千条记录。它将输入读入dataTable
并逐行运行SQL命令:
for(int i = 0; i < dataTable.Rows.Count; i++)
{
string sqlConnectionString = "server, db, user, pass, etc.";
SqlConnection sqlDBConnection = new SqlConnection(sqlConnectionString);
string query = @"INSERT INTO table
(col1, col2, col3, etc.)
VALUES
(@col1, @col2, @col3, etc.)";
SqlCommand queryCommand = new SqlCommand(query, sqlDBConnection);
queryCommand.Parameters.Add("@col1", SqlDbType.Int);
queryCommand.Parameters["@col1"].Value = Convert.ToInt32(dataTable.Rows[i][0]);
queryCommand.Parameters.Add("@col2", SqlDbType.VarChar);
queryCommand.Parameters["@col2"].Value = dataTable.Rows[i][1].ToString();
queryCommand.Parameters.Add("@col3", SqlDbType.VarChar);
queryCommand.Parameters["@col3"].Value = dataTable.Rows[i][2].ToString();
sqlDBConnection.Open();
queryCommand.ExecuteNonQuery();
sqlDBConnection.Close();
}
它工作得很好,但速度很慢。你有更快的解决方案吗?
答案 0 :(得分:1)
使用批量插入SqlBulkCopy Class或Table Valued Parameters in C# 这应该加快速度
答案 1 :(得分:1)
由于您的数据已经在DataTable中,我认为最好的方法是使用SQLBulkCopy。 e.g。
string sqlConnectionString = "server, db, user, pass, etc.";
using (var bulkCopy = new SqlBulkCopy(sqlConnectionString))
{
bulkCopy.DestinationTableName = "table";
bulkCopy.ColumnMappings.Add("Col1", "Col1");
bulkCopy.ColumnMappings.Add("Col2", "Col2");
bulkCopy.ColumnMappings.Add("Col3", "Col3");
bulkCopy.WriteToServer(dataTable);
}
要更新现有记录,如果使用SqlDataAdapter填充了DataTable,则可以使用SqlDataAdapter.Update()
方法。如果没有,那么我建议在SQL中处理upsert。由于您使用的是SQL Server 2012,因此可以使用表值参数。第一步是创建Table type
CREATE TYPE dbo.YourTableType TABLE
(
Col1 INT,
Col2 INT,
Col3 INT
);
这应该与c#DataTable具有相同的定义。
然后下一步是创建一个接受此类型作为参数的存储过程,并使用MERGE
根据是否匹配来插入或更新记录:
CREATE PROCEDURE dbo.UpsertYourTable @Table dbo.YourTableType READONLY
AS
BEGIN
MERGE dbo.YourTable WITH (HOLDLOCK) AS t
USING @Table AS s
ON s.Col1 = t.Col1 -- OR HOWEVER YOU IDENTIFY EXISTING RECORDS
WHEN MATCHED THEN UPDATE
SET Col2 = Col2,
Col3 = Col4
WHEN NOT MATCHED THEN
INSERT (Col1, Col2, Col3, Col4)
VALUES (s.Col1, s.Col2, s.Col3, 'Test');
END;
GO
最后,要从c#中调用它,您将使用:
string sqlConnectionString = "server, db, user, pass, etc.";
using (var connection = new SqlConnection(sqlConnectionString))
using (var command = new SqlCommand("dbo.UpsertYourTable", connection))
{
command.CommandType = CommandType.StoredProcedure;
var tvp = new SqlParameter("@Table", SqlDbType.Structured);
tvp.Value = dataTable;
tvp.TypeName = "dbo.YourTableType";
command.Parameters.Add(tvp);
command.ExecuteNonQuery();
}
答案 2 :(得分:0)
这很慢,因为每个插入都是自己的treatet,这会导致事务时间的开销。 尝试使用不同的方法进行批量插入。 无论是在框架上(如弹簧数据批量)还是仅通过更改查询以一次插入多个值。
insert into table (col1, col2, col3, ...)
values (val1, val2, cal3, ...),
(val1, val2, cal3, ...),
(val1, val2, cal3, ...), ...
但是不要将它们全部联系起来,不要监督db-connection的缓冲区大小。
答案 3 :(得分:0)
您是否考虑过使用SSIS?或通过Bulk Insert
。无论您选择哪种选项,您都希望最大限度地减少进入数据库的连接数 - 一旦数千次调用将会非常密集。