2013-02-26 73 views
0

我正在做一个循环插入,如下所示(方法A),似乎每个循环调用数据库不是一个好主意。我发现一种替代方法是在我的SProc中循环逗号分隔的字符串,而不是执行插入操作,以便只有一个条目进入数据库。在性能方面会有什么重大改进? :SQL Server +循环插入性能

方法A:

foreach (DataRow row in dt.Rows) 
{ 
    userBll = new UserBLL(); 
    UserId = (Guid)row["UserId"]; 
    // Call userBll method to insert into SQL Server with UserId as one of the parameter. 
} 

方法B:

string UserIds = "Tom, Jerry, 007"; // Assuming we already concatenate the strings. So no loops this time here. 
userBll = new UserBLL(); 
// Call userBll method to insert into SQL Server with 'UserIds' as parameter. 

方法B SPROC /执行在SPROC环插入件。

if right(rtrim(@UserIds), 1) <> ',' 
    SELECT @string = @UserIds + ',' 

SELECT @pos = patindex('%,%' , @UserIds) 

while @pos <> 0 
begin 
    SELECT @piece = left(@v, (@pos-1)) 

    -- Perform the insert here 

    SELECT @UserIds = stuff(@string, 1, @pos, '') 
    SELECT @pos = patindex('%,%' , @UserIds) 
end 
+0

我假设SQL Server - 如果是这样,哪个版本? – Bridge 2013-02-26 15:00:16

+0

这是SQL Server 2008R2 – k80sg 2013-02-26 15:00:44

+0

您也可以通过'方法B + XML'将CSV值作为行返回,而不循环,然后执行INSERT INTO TABLE SELECT * FROM ... – 2013-02-26 15:13:57

回答

1

较少的查询通常意味着更快的处理。也就是说,我的一名同事在.NET框架的TSQL BULK INSERT的包装上取得了一些成功,该框架由框架提供为SqlBulkCopyThis MSDN blog entry shows how to use it

主要“API”的样品是这样(按原样,将其写入DataTable添加到SQL的内容从链接的文章取):

private void WriteToDatabase() 
{ 
    // get your connection string 
    string connString = ""; 
    // connect to SQL 
    using (SqlConnection connection = 
      new SqlConnection(connString)) 
    { 
     // make sure to enable triggers 
     // more on triggers in next post 
     SqlBulkCopy bulkCopy = 
      new SqlBulkCopy 
      (
      connection, 
      SqlBulkCopyOptions.TableLock | 
      SqlBulkCopyOptions.FireTriggers | 
      SqlBulkCopyOptions.UseInternalTransaction, 
      null 
      ); 

     // set the destination table name 
     bulkCopy.DestinationTableName = this.tableName; 
     connection.Open(); 

     // write the data in the "dataTable" 
     bulkCopy.WriteToServer(dataTable); 
     connection.Close(); 
    } 
    // reset 
    this.dataTable.Clear(); 
    this.recordCount = 0; 
} 

链接的文章解释了需要做什么利用这种机制。

0

如果您正在寻找与给定类型的多个输入值更好的插入性能,我建议你看一下table valued parameters

和样品,可以发现here,显示出使用它们的一些示例代码。

1

根据我的经验,也有你不希望有每个记录做三件事情:

  1. 打开/关闭每一个SQL连接行。这个问题由ADO.NET连接池处理。除非您禁用了池,否则您不必担心它。

  2. 数据库每行往返。这往往不太关于网络带宽或网络延迟,更多的是关于客户端线程休眠。每次唤醒时您都需要在客户端进行大量的工作,或者您正在浪费时间片。

  3. 打开/关闭每行的sql事务日志。打开和关闭日志并不是免费的,但你也不想太长时间地打开它。在单个事务中执行多次插入,但不是太多。

对于其中的任何一种,您可能会看到很多改进,从每个请求1行到每个请求10行。您可以通过在传输批次之前在客户端建立10条插入语句来实现此目的。

您将一个列表发送到proc的方法已经被Sommarskog写入极端深度。