执行存储过程时,使用CommandType.StoredProcedure与使用CommandType.Text有什么好处?

MAW*_*656 15 c# sql database sql-server

所以在C#中使用存储过程我有如下代码(省略连接代码):

 string sql = "GetClientDefaults";

 SqlCommand cmd = new SqlCommand(sql);
 cmd.CommandType = CommandType.StoredProcedure;    //<-- DO I NEED THIS??
 cmd.Parameters.AddWithValue("@computerName", computerName);
Run Code Online (Sandbox Code Playgroud)

其中sql是存储过程的名称.现在,这个代码似乎在有和没有注释行的情况下工作得很好.

那么,我需要这条线吗?设置它有一些性能(或其他)的好处吗?不设置或将其设置为文本是否有益处?

And*_*ren 15

根据此博客文章中的测试,SQL Server将为您执行参数化,方法是在使用时将语句包装在sp_executesql中CommandType.Text.但是当你使用时,CommandType.StoredProcedure你将参数化它,从而节省数据库的一些工作.后一种方法更快.

编辑:

建立

我自己做了一些测试,这是结果.

创建此过程:

create procedure dbo.Test
(
   @Text1 varchar(10) = 'Default1'
  ,@Text2 varchar(10) = 'Default2'
)
as
begin
   select @Text1 as Text1, @Text2 as Text2
end
Run Code Online (Sandbox Code Playgroud)

使用SQL Server Profiler向其添加跟踪.

然后使用以下代码调用它:

using System;
using System.Data;
using System.Data.SqlClient;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main()
        {
            CallProcedure( CommandType.Text );
            CallProcedure( CommandType.StoredProcedure );
        }

        private static void CallProcedure(CommandType commandType)
        {
            using ( SqlConnection connection = new SqlConnection("Data Source=localhost;Initial Catalog=Test;Integrated Security=SSPI;") )
            {
                connection.Open();
                using ( SqlCommand textCommand = new SqlCommand("dbo.Test", connection) )
                {
                    textCommand.CommandType = commandType;
                    textCommand.Parameters.AddWithValue("@Text1", "Text1");
                    textCommand.Parameters.AddWithValue("@Text2", "Text2");
                    using ( IDataReader reader = textCommand.ExecuteReader() )
                    {
                        while ( reader.Read() )
                        {
                            Console.WriteLine(reader["Text1"] + " " + reader["Text2"]);
                        }
                    }
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结果

在这两种情况下,调用都是使用RPC进行的.

以下是跟踪显示的内容CommandType.Text:

exec sp_executesql N'dbo.Test',N'@Text1 nvarchar(5),@Text2 nvarchar(5)',@Text1=N'Text1',@Text2=N'Text2'
Run Code Online (Sandbox Code Playgroud)

以下是使用的结果CommandType.StoredProcedure:

exec dbo.Test @Text1=N'Text1',@Text2=N'Text2'
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,文本调用包含在调用中,sp_executesql以便正确地进行参数化.这当然会产生轻微的开销,因此我之前声明使用CommandType.StoredProcedure更快仍然有效.

另一个值得注意的事情,也就是这里的交易破坏者,是当我创建没有默认值的过程时,我得到以下错误:

消息201,级别16,状态4,过程测试,行0过程或函数"测试"期望参数'@ Text1',未提供.

这样做的原因是如何sp_executesql创建调用,因为您可以看到参数已声明并初始化,但它们未被使用.对于工作电话,它应该看起来像这样:

exec sp_executesql N'dbo.Test @Text1, @Text2',N'@Text1 nvarchar(5),@Text2 nvarchar(5)',@Text1=N'Text1',@Text2=N'Text2'
Run Code Online (Sandbox Code Playgroud)

这意味着,当您使用时,CommandType.Text您必须将参数添加到CommandText除非您始终希望使用默认值.

所以,回答你的问题

  1. 使用CommandType.StoredProcedure速度更快.
  2. 如果您正在使用CommandType.Text,则必须将参数名称添加到对过程的调用中,除非您希望使用默认值.


Rem*_*anu 7

实际上存在巨大差异.如果指定命令类型,StoredProcedure则添加到SqlCommand的任何参数都将是添加过程调用的参数.如果将其保留为,Text则参数将添加到批处理中,而不是添加到过程中.为了说明这一点,让我们创建一个虚拟过程:

create procedure usp_test 
    @p1 char(10)  = 'foo',
    @p2 int = 42
as
    select @p1, @p2;    
go
Run Code Online (Sandbox Code Playgroud)

然后编译这个小小的C#应用​​程序:

   static void Main(string[] args)
    {
        ExecWithType(CommandType.Text);
        ExecWithType(CommandType.StoredProcedure);
    }

    static void ExecWithType(CommandType type)
    {
        using (SqlConnection conn = new SqlConnection(Settings.Default.connString))
        {
            conn.Open();
            using (SqlCommand cmd1 = new SqlCommand("usp_test", conn))
            {
                cmd1.CommandType = type;
                cmd1.Parameters.AddWithValue("@p1", "bar");
                cmd1.Parameters.AddWithValue("@p2", 24);
                using (SqlDataReader rdr = cmd1.ExecuteReader())
                {
                    while (rdr.Read())
                    {
                        Console.WriteLine("Type: {0} Result: @p1: {1} @p2: {2}", type, rdr[0], rdr[1]);
                    }
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

结果是:

Type: Text Result: @p1: foo        @p2: 42
Type: StoredProcedure Result: @p1: bar        @p2: 24
Run Code Online (Sandbox Code Playgroud)

哎哟! 对于CommandType.Text设置虽然参数已传递给批处理,但它们未传递给过程.多小时调试乐趣的来源......

  • - 所以有了参数,没有灰色地带,CommandType.StoredProcedure 肯定更好,更准确,更快。 (2认同)

小智 6

您可以将其设置为允许ADO.NET帮助您.使用时CommandType.StoredProcedure,您必须将CommandText存储过程名称等于.

例如,这个:

YourSqlCommand.CommandType = CommandType.StoredProcedure;
YourSqlCommand.CommandText = "dbo.YourStoredProc";
Run Code Online (Sandbox Code Playgroud)

相当于:

YourSqlCommand.CommandText = "exec dbo.YourStoredProc";
Run Code Online (Sandbox Code Playgroud)

  • @ MAW74656那是因为在SQL Server中,如果存储过程是批处理的第一个语句,则不必键入`exec`. (4认同)