SqlServer更好地批处理语句还是foreach?

时间:2011-05-04 04:13:34

标签: sql-server ado.net

假设,将N语句发送到Sql Server(2008)是否更好,或者将包含N语句的1个命令发送到Sql Server更好?在任何一种情况下,我在对象列表上运行相同的语句,在这两种情况下,我将使用命名参数。假设我的用例每隔几个小时就会转储一个日志项缓存。

foreach示例

var sql = "update blah blah blah where id = @id";
using(var conn = GetConnection())
{
    foreach(var obj in myList)
    {
         var cmd = new SqlCommand() 
         {CommandText = sql, Connection = conn};
         //add params from obj
         cmd.ExecuteNonQuery();
    }
}

批量示例

var sql = @"
   update blah blah blah where id = @id1
   update blah blah blah where id = @id2
   update blah blah blah where id = @id3
   -etc";
 using (var conn = GetConnection())
 {
     var cmd = new SqlCommand
     { CommandText = sql, Connection = conn};

     for(int i=0; i<myList.Count; i++)
     {
         //add params: "id" + i  from myList[i]
     }
     cmd.ExecuteNonQuery();
 }

在时间测试中,批量版本比大型输入的foreach版本长15%。我认为批处理版本需要更长的时间来执行,因为服务器必须解析一个巨大的语句并绑定多达2000个参数。假设Sql Server在局域网上,使用批处理方法有什么优势吗?

2 个答案:

答案 0 :(得分:0)

您的测试似乎已经给了您答案,但让我添加另一个。最好将更新封装到单独的函数中,并使用foreach调用它:

private function UpdateFoo( int id )
{
    const sql = "Update Foo Where Id = @Id";
    using ( var conn = GetConnection() )
    {
        using ( var cmd = new SqlCommand( sql, conn ) )
        {
            cmd.AddParameterWithValue( "@Id", id )
            cmd.ExecuteNonQuery();
        }
    }
}

private function UpdateLotsOfFoo()
{
    foreach( var foo in myList )
    {
        UpdateFoo( foo.Id );
    }
}

在此设置中,您正在利用连接池,这可以降低打开和关闭连接的成本。

答案 1 :(得分:0)

@Thomas - 这种设计会增加循环中打开/关闭连接的开销。这不是优选的做法,应该避免。下面的代码允许在使用一个连接时迭代语句,并且在资源(客户端和服务器端)上更容易。

    private void UpdateFoo(int id)
    {
        const string sql  = "Update Foo Where Id = @Id";
        using (var conn = GetConnection())
        {
            conn.Open();
            foreach (var foo in myList)
            {
                UpdateFoo(foo.Id);
                using (var cmd = new SqlCommand(sql, conn))
                {
                    cmd.AddParameterWithValue("@Id", id);
                    cmd.ExecuteNonQuery();
                }
            }
            conn.Close();

        }
    }