2012-02-24 83 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

相關問題