2012-02-24 85 views
1

我有使用存储过程插入SQL Server数据库的记录列表。目前我正在这样做,但有没有更好的办法?使用存储过程在数据库中插入列表记录

我在应用程序的高峰时段插入100-200行/秒。该存储过程只得到了价值和插入新行,你可以做

public void InsertRecords(List<stRecord> records) 
    { 
     foreach (var item in records) 
     { 
      if (CheckforDuplicateRecord(item) == false) 
      { 
       using (con = new SqlConnection(connectionString)) 
       { 
        con.Open(); 

        SqlCommand cmd = new SqlCommand(StoredProcedures.Service_Insert_record.ToString(), con); 
        cmd.CommandType = CommandType.StoredProcedure; 

        cmd.Parameters.Add("@item1", SqlDbType.NChar); 
        cmd.Parameters.Add("@item2", SqlDbType.NChar); 

        cmd.Parameters[0].Value = item.localUsername; 
        cmd.Parameters[1].Value = item.BetfairUsername; 


        try 
        { 
         cmd.ExecuteNonQuery(); 
        } 
        catch (Exception exp) 
        { 
         throw exp; 
        } 
       } 
      } 
     } 
    } 
+0

您是否在寻找更好的性能,代码改进,无论是还是? – Dan 2012-02-24 21:29:25

+0

两种方式如果可能的话,我是非常新的C#我不知道它是否正确的编码方式,假设我们有200个记录,我们打开数据库连接200次,然后关闭它,插入记录一个,有一些更好的编码?用于内存改进或永久性 – kawafan 2012-02-24 21:31:51

+0

您正在使用哪个版本的Sql Server? – 2012-02-24 21:34:01

回答

7

这正是表值参数的用途 - 您可以一次性传递列表。

在SQL Server:

CREATE TYPE dbo.Usernames AS TABLE 
(
    localUsername NVARCHAR(32), 
    BetfairUsername NVARCHAR(32) 
); 
GO 

CREATE PROCEDURE dbo.Service_Insert_MultipleRows 
    @u AS dbo.Usernames READONLY 
AS 
BEGIN 
    SET NOCOUNT ON; 

    INSERT INTO dbo.DestinationTable(localUsername, BetfairUsername) 
    SELECT localUsername, BetfairUsername FROM @u; 
END 
GO 

现在,在C#:

DataTable tvp = new DataTable(); 
tvp.Columns.Add(new DataColumn("localUsername")); 
tvp.Columns.Add(new DataColumn("BetfairUsername")); 

foreach(var item in records) 
{ 
    tvp.Rows.Add(item.localUsername, item.BetfairUsername); 
} 

using (con) 
{ 
    SqlCommand cmd = new SqlCommand("Service_Insert_MultipleRows", con); 
    cmd.CommandType = CommandType.StoredProcedure; 
    SqlParameter tvparam = cmd.Parameters.AddWithValue("@u", tvp); 
    tvparam.SqlDbType = SqlDbType.Structured; 
    con.Open(); 
    cmd.ExecuteNonQuery(); 
} 
+0

我想多次投票! – Steve 2012-02-24 22:17:19

+0

这是更好的想法,它是否也提高了性能? – kawafan 2012-02-24 22:40:02

+0

绝对如此。您只需建立一个到数据库的连接,调用一个过程,并将数据作为单个流发送。 – 2012-02-24 23:24:46

0

一个显而易见的事情:创建SqlCommand一次在方法的开始 - 没有任何意义了一遍又一遍又一遍创造它再次!

public void InsertRecords(List<stRecord> records) 
{ 
    using (con = new SqlConnection(connectionString)) 
    using (SqlCommand cmd = new SqlCommand(StoredProcedures.Service_Insert_record.ToString(), con)) 
    { 
     cmd.CommandType = CommandType.StoredProcedure; 

     // are those paramters *REALLY* just 1 character long?? 
     // that's what you have now, with the way you define it! 
     cmd.Parameters.Add("@item1", SqlDbType.NChar); 
     cmd.Parameters.Add("@item2", SqlDbType.NChar); 

     // otherwise, you need to define the LENGTH of the NCHAR parameter! 
     // cmd.Parameters.Add("@item2", SqlDbType.NChar, 15); 

     foreach (var item in records) 
     { 
      if (CheckforDuplicateRecord(item) == false) 
      { 
       cmd.Parameters["@item1"].Value = item.localUsername; 
       cmd.Parameters["@item2"].Value = item.BetfairUsername; 

       try 
       { 
       con.Open(); 
       cmd.ExecuteNonQuery(); 
       con.Close(); 
       } 
       catch (Exception exp) 
       { 
       throw; 
       } 
      } 
     } 
    } 
+0

打开连接200次没有什么不对吗?在1秒内?并且这种情况不断发生,因为它是一个Web服务 – kawafan 2012-02-24 21:56:21

+0

@ user353600:ADO.NET连接被集中,因此“打开”和“关闭”它们并不是一个真正的大操作。但是,是的 - 你也可以尝试在'foreach'之前打开连接 - 只是在异常情况下处理错误更复杂一些。 – 2012-02-24 22:06:09

相关问题