При выполнении хранимой процедуры, каково преимущество использования CommandType.StoredProcedure по сравнению с использованием CommandType.Text? - PullRequest
15 голосов
/ 13 февраля 2012

Таким образом, в C # для использования хранимой процедуры у меня есть код, подобный следующему (код подключения опущен):

 string sql = "GetClientDefaults";

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

Где sql - имя хранимой процедуры. Теперь этот код, кажется, прекрасно работает с закомментированной строкой и без нее.

Итак, мне нужна эта строка? Есть ли какое-то преимущество в производительности (или другое) для настройки этого? Есть ли преимущество в том, чтобы НЕ устанавливать его или устанавливать его в текст?

Ответы [ 4 ]

15 голосов
/ 14 февраля 2012

Согласно тестам в в этом блоге SQL Server выполнит параметризацию за вас, обернув ваше утверждение в sp_executesql, когда вы используете CommandType.Text. Но когда вы используете CommandType.StoredProcedure, вы его параметризуете и тем самым сохраняете базу данных некоторую работу. Последний способ быстрее.

Edit:

Настройка

Я сам провел несколько тестов, и вот результаты.

Создать эту процедуру:

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

Добавить трассировку к нему с помощью 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"]);
                        }
                    }
                }
            }
        }
    }
}

Результаты

В обоих случаях звонки осуществляются с использованием RPC.

Вот что показывает трассировка, используя CommandType.Text:

exec sp_executesql N'dbo.Test',N'@Text1 nvarchar(5),@Text2 nvarchar(5)',@Text1=N'Text1',@Text2=N'Text2'

А вот результат использования CommandType.StoredProcedure:

exec dbo.Test @Text1=N'Text1',@Text2=N'Text2'

Как видите, текстовый вызов обернут в вызов 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'

То есть, когда вы используете CommandType.Text, вам нужно добавить параметры в CommandText, если вы не хотите всегда использовать значения по умолчанию.

Итак, чтобы ответить на ваш вопрос

  1. Использование CommandType.StoredProcedure быстрее.
  2. Если вы используете CommandType.Text, вам придется добавить имена параметров к вызову процедуры, если вы не хотите использовать значения по умолчанию.
7 голосов
/ 14 февраля 2012

На самом деле есть огромная разница.Если вы укажете тип команды StoredProcedure, то любой параметр, который вы добавите в SqlCommand, будет параметром, добавленным в вызов процедуры .Если вы оставите его как Text, то параметры будут добавлены в партию , а не в процедуру.Чтобы проиллюстрировать это, давайте создадим фиктивную процедуру:

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

Затем скомпилируем это крошечное приложение 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]);
                    }
                }
            }
        }
    }

Результат:

Type: Text Result: @p1: foo        @p2: 42
Type: StoredProcedure Result: @p1: bar        @p2: 24

Ой! Для настройки CommandType.Text, хотя параметры были переданы в партию , они не были переданы в процедуру .Источник многих часов отладки веселья ...

6 голосов
/ 13 февраля 2012

Вы должны установить это, чтобы ADO.NET помог вам. Когда вы используете CommandType.StoredProcedure, вам нужно просто поставить CommandText равным имени хранимой процедуры.

Например, это:

YourSqlCommand.CommandType = CommandType.StoredProcedure;
YourSqlCommand.CommandText = "dbo.YourStoredProc";

Эквивалентно:

YourSqlCommand.CommandText = "exec dbo.YourStoredProc";
3 голосов
/ 14 февраля 2012

CommandType не является специфическим для SQL Server. Это свойство интерфейса IDbCommand , которое инструктирует основного поставщика обрабатывать CommandText определенным образом. Хотя SQL Server может обрабатывать имена из одного слова как процедуры, не следует ожидать, что это будет работать в других провайдерах.

В целом, вы должны предпочесть использовать сгенерированные провайдером классы, такие как DbCommand, а не определенные классы, такие как SqlCommand. Таким образом, вы можете настроить таргетинг на разные базы данных, просто изменив строку поставщика в вашем конфигурационном файле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...