Sql server SqlServer比批处理语句或foreach更好?
假设,向Sql Server 2008发送N条语句更好,还是向Sql Server发送包含N条语句的1条命令更好?在这两种情况下,我都在对象列表上运行相同的语句,在这两种情况下,我都将使用命名参数。假设我的用例每隔几个小时转储一次日志项缓存 每个例子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) {
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语句的命令,来更加强调数据库。你怎么认为?