我有一组需要插入SQL Server 2005表的对象(存储在链表中)。
这里的解决方案非常慢。我有大约10K的记录要插入。每隔一段时间我就会暂停,只看到更多的执行完成。
有人可以帮助改善这个吗?
using (SqlConnection dbConnection = new SqlConnection(connectionString))
{
dbConnection.Open();
SqlTransaction dbTrans = dbConnection.BeginTransaction();
SqlCommand cmd = dbConnection.CreateCommand();
cmd.Transaction = dbTrans;
foreach (MyRecord myr in Records)
{
cmd.CommandText = buildInsertionString(MyRecord)
cmd.ExecuteNonQuery();
}
dbTrans.Commit();
dbConnection.Close();
}
public string buildinsertionString(Myrecod myr){
string sqlCommandString = "insert into Table1 values";
string values = "'" + myr.field1 + "',"
+ myr.field2 + ","
+ "'" + myr.field3 + "',"
+ "'" + myr.field4 + "',"
+ "'" + myr.field5 + "',"
+ "'" + myr.field6 + "'";
return sqlCommandString + "(" + values + ");
}
答案 0 :(得分:5)
使用SQLBulkCopy
(System.Data.SqlClient
):
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn))
{
bulkCopy.DestinationTableName = "table";
bulkCopy.WriteToServer(Records);
}
}
生成的SQL使用SQL Server 2005及更新版本中的BULK INSERT
命令和功能。
注意:Records
必须是DataRow
,DataTable
类型,或者使用IDataReader
。
答案 1 :(得分:2)
您可以对代码进行的唯一改进是参数化由buildInsertionString方法构建的insert语句,以便insert语句可以编译一次,并由链接列表中每个记录的所有后续调用重用。例如:
String insert = "insert into table (field) values (@value)";
cmd.Parameters.AddWithValue("@value",element);
答案 2 :(得分:0)
一种简单的方法是使用将用户定义的表类型传递给存储过程。如果您需要为复制记录的事务,并且您有标识列或未提供表中的所有列,则这比BulkInsert更好。使用上面的代码作为示例,它看起来像这样:
在Sql Server上:
Create Type dbo.MyRecord As Table
(
field1 Varchar(50), -- Or whatever your types and names are
field2 Varchar(50),
field3 Varchar(50),
field4 Varchar(50),
field5 Varchar(50),
field6 Varchar(50)
)
Go
Create Procedure dbo.spInsertTable1
(
@vals dbo.MyRecord ReadOnly
)
As
Begin
Insert Into dbo.Table1(field1, field2, field3, field4, field5, field6)
Select field1, field2, field3, field4, field5, field6
From @vals
End
Go
在c#侧:
using System.Linq;
....
using (SqlConnection dbConnection = new SqlConnection(connectionString))
{
dbConnection.Open();
SqlTransaction dbTrans = dbConnection.BeginTransaction();
using(SqlCommand cmd = new SqlCommand("dbo.spInsertTable1", dbConnection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Transaction = dbTrans;
var records = Records.Select(it =>
new {
field1 = it.field1,
field2 = it.field2,
field3 = it.field3,
field4 = it.field4,
field5 = it.field5,
field6 = it.field6
}).ToDataTable();
var param = cmd.Parameters.AddWithValue("@vals", records);
param.TypeName = "dbo.MyRecord";
cmd.ExecuteNonQuery();
}
dbTrans.Commit();
}
public DataTable ToDataTable<T>(IEnumerable<T> data)
{
PropertyDescriptorCollection props =
TypeDescriptor.GetProperties(typeof(T));
if (props == null) throw new ArgumentNullException("Table properties.");
if (data == null) throw new ArgumentNullException("data");
DataTable table = new DataTable();
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item) ?? DBNull.Value;
}
table.Rows.Add(values);
}
return table;
}
答案 3 :(得分:-4)
您可以将GO语句建立为由GO命令分开的单个字符串,并一次性发送它们。这应该快得多。
StringBuilder sb = new StringBuilder();
foreach(Thing thing in Something)
{
string query = BuildMyQuery(thing);
sb.Append(query);
sb.Append("GO");
}
string SQLText = sb.ToString();
// Execute SQL Command here using SQL Text