Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我应该如何优化.net代码中对一个普通存储过程的多个调用?_.net_Sql_Optimization_Stored Procedures - Fatal编程技术网

我应该如何优化.net代码中对一个普通存储过程的多个调用?

我应该如何优化.net代码中对一个普通存储过程的多个调用?,.net,sql,optimization,stored-procedures,.net,Sql,Optimization,Stored Procedures,我有一个非常简单的存储过程: create procedure spFoo(v varchar(50)) as insert into tbFoo select v 我有50个值要插入到tbFoo中,这意味着在我的c#代码中我调用spFoo 50次。这是一种非常低效的方法,尤其是当我的程序和数据库之间存在一些延迟时 在这种情况下你通常做什么 我使用的是SQL Server 2008,但可能与此无关。这取决于这是否是性能瓶颈。 如果不是,我就不会担心了 如果是,您可以将所有50项传递给一个存储

我有一个非常简单的存储过程:

create procedure spFoo(v varchar(50))
as 
insert into tbFoo select v
我有50个值要插入到tbFoo中,这意味着在我的c#代码中我调用spFoo 50次。这是一种非常低效的方法,尤其是当我的程序和数据库之间存在一些延迟时

在这种情况下你通常做什么


我使用的是SQL Server 2008,但可能与此无关。

这取决于这是否是性能瓶颈。
如果不是,我就不会担心了

如果是,您可以将所有50项传递给一个存储过程,例如一个字符串。
然后,存储过程可以拆分这些值,然后根据需要调用您的创建过程。

因此,您只需调用一次SQL,它就可以执行50次插入操作。

实际上,这里的效率低下是什么?如果您不想使用任何类型的批量插入,则必须调用它50次。然而,如果您使用一个准备好的语句,并且每次运行时只替换参数值,那么它应该运行得非常快


此外,50个insert/sp调用实际上什么都不是。马上就可以了。

传递要作为XML参数插入的值。然后可以使用XPath查询大容量插入数据。

实际上,SQLServer2008的一个很酷的功能是

设置:

create type fooTableType as table (v varchar(50));
go 

create proc spFoo(@t fooTableType readonly) as
  insert into tbFoo(v) select v from @t
go
然后你的C代码族:

declare @t as fooTableType
insert @t(v) values('beyond'),('all'),('recognition')
exec spFoo(@t)
下面是一些粗略的C代码:

using (SqlCommand cmd=new SqlCommand()) {
  StringBuilder sql = new StringBuilder();
  for(int i=0; i<50; i++) {
    sql.AppendFormat(",(@v{i})",i);
    cmd.Parameters.AddWithValue("@v"+i.ToString(),values[i]);
  }
  cmd.CommandText = "declare @t as fooTableType; insert @t(v) values" +
                    sql.ToString().Substr(1) + "; exec spFoo(@t);"
  cmd.CommandType = CommandType.Text;
  cmd.Connection = myConnection;
  cmd.ExecuteNonQuery();
}
使用(SqlCommand cmd=new SqlCommand()){
StringBuilder sql=新的StringBuilder();

对于(int i=0;i通过在@v0到@v49之间创建参数来批处理调用,因此只有1个网络往返:

using (var cmd = new SqlCommand()) {
   for (int i = 0; i < 50; i++) {
      string paramName = "@v" + i.ToString();
      cmd.CommandText += string.Format("EXEC spFoo " + paramName + ";");
      cmd.Parameters.AddWithValue(paramName, values[i]);
   }

   cmd.ExecuteNonQuery();
}
使用(var cmd=new SqlCommand()){
对于(int i=0;i<50;i++){
字符串paramName=“@v”+i.ToString();
cmd.CommandText+=string.Format(“EXEC spFoo”+paramName+“;”);
cmd.Parameters.AddWithValue(paramName,value[i]);
}
cmd.ExecuteNonQuery();
}

如果您的问题是多行试图传入,那么从SQL Server 2008开始,您有了一个新的参数类型。它允许您通过结构化类型的.Net SqlParameter将.Net数据表直接传入存储过程

tvpParam.SqlDbType = SqlDbType.Structured
但是,如果问题是您试图填充的一行中有50列,那么最好将它们作为单独的参数传递进来,并更改过程,而不是尝试使用代码或T-SQL

有一个很好的例子演示了如何在SQL Server中使用表值参数,以及如何通过.NET在C#和VB.NET中使用表值参数。
希望这能有所帮助。

我将列表构造为xml字符串,并将其传递给存储过程。在SQL 2005中,它具有良好的xml功能来解析xml并进行大容量插入

查看此帖子:

你能从.NET代码中调用此存储过程吗?如果可以,你介意发布一些示例代码来演示如何进行吗?谢谢。事实上,我找到了:。好东西在我看来,这不像其他代码那样整洁或可维护。我实际上更喜欢预先准备命令并循环50次,只需更改参数。或者更好的是,使用TVPARAM.SqlDbType=SqlDbType。按照CertifiedCrazy的答案进行结构。有趣的是…没有见过这种方法before@MarkBrackett向上投票!这是一个适合我的项目需求的完美方法