Sql server SqlServer比批处理语句或foreach更好?

Sql server SqlServer比批处理语句或foreach更好?,sql-server,ado.net,Sql Server,Ado.net,假设,向Sql Server 2008发送N条语句更好,还是向Sql Server发送包含N条语句的1条命令更好?在这两种情况下,我都在对象列表上运行相同的语句,在这两种情况下,我都将使用命名参数。假设我的用例每隔几个小时转储一次日志项缓存 每个例子 var sql = "update blah blah blah where id = @id"; using(var conn = GetConnection()) { foreach(var obj in myList) {

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

每个例子

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();
 }
批处理示例

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在局域网上,使用批处理方法有什么好处吗?

您的测试似乎已经给出了答案,但让我再补充一个。最好将更新封装到单独的函数中,并使用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 );
    }
}

在此设置中,您将利用连接池来降低打开和关闭连接的成本

@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();

        }
    }

如果可以的话,我建议您使用for语句而不是for语句。根据更新逻辑的复杂性,我可能会选择使用id列表填充临时表,然后更新select id from temp中的id。如果我不关心索引,为什么for循环更好?这使用post上的连接池?我认为这意味着可以利用准备好的语句/缓存?@pst-不同的问题。首先,在连接池中烘焙ADO.NET和ADO之前。因此,一般来说,最好打开一个连接,做一些工作,然后尽快关闭以将其返回到池中。直到后来ADO.NET才真正关闭连接。准备好的语句通常由SQL Server或数据库引擎完成。“当您使用参数化查询时,您就会得到它。@thomas在任何一种情况下,我都会得到一个连接,打开它,运行我的命令,然后处理它。”。我不明白在每个循环迭代中向池请求一个潜在的新连接如何更好。@dan-因为实际上您并没有得到一个新连接。您正在获得一个已打开的连接。这样做更好的原因是封装。它允许您重用updatefo。另一个原因是,您以后可能会迁移到使用多线程(如Parallel.ForEach)并封装updatefo,这会更容易。好的,在这种情况下,更新是在后台线程中运行的,它只是转储一堆日志数据。我主要关心的是,我是通过发送每个语句包含一条语句的2k命令,还是发送一条包含2k语句的命令,来更加强调数据库。你怎么认为?