质量INSERT的问题

时间:2011-09-11 18:29:49

标签: c# sql-server sql-server-2005 tsql

我有一组需要插入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 + ");

}

4 个答案:

答案 0 :(得分:5)

使用SQLBulkCopySystem.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必须是DataRowDataTable类型,或者使用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