Выполняются ли хранимые процедуры из текстовой строки?

Есть несколько SQL-серверов с хранимыми процедурами, например Microsoft SQL Server или PostgreSQL. Есть также несколько клиентских объектов, реализующих вызовы хранимых процедур (TADOStoredProc в Delphi, SqlCommand в .NET Framework и т. д.).

Всегда хотел задать вопрос:

хранимые процедуры всегда выполняются особым эффективным способом с бинарным представлением их параметров или представляют собой сверхпродвинутые объекты, которые представляют параметры хранимых процедур, всегда преобразованные в простую текстовую строку, и хранимая процедура всегда выполняется путем отправки этой текстовой строки на сервер SQL ? (Возьмем для примера одну технологию — пусть это будет SQL Server и ADO.NET).

Я заметил, что для ADO.NET имена параметров процедуры не имеют никакого значения - важен только порядок их создания, что наводит меня на мысль об идее с простой текстовой строкой.

Обновление для @Alex K.

Я протестировал следующий код в .NET:

CREATE PROCEDURE paramtest
@par1 nvarchar(50),
@par2 nvarchar(50),
@par3 nvarchar(50)
AS
  SELECT Res = '@par1 = ' + @par1 + '; @par2 = ' + @par2 + '; @par3 = ' + @par3
  RETURN 555

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

namespace SqlParamTest
{
    class Program
    {
        private static void addParam(SqlCommand cmd, string parameterName, ParameterDirection direction, SqlDbType dbType, int size, object value)
        {
            SqlParameter par = new SqlParameter(parameterName, dbType, size);
            par.Direction = direction;
            par.Value = value;
            cmd.Parameters.Add(par);
        }

        static void Main(string[] args)
        {
            using (SqlConnection conn = new SqlConnection(@"Data Source=localhost\sqlexpress;Initial Catalog=test;Integrated Security=True"))
            {
                SqlCommand cmd = conn.CreateCommand();
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.CommandText = "paramtest";
                addParam(cmd, "@par3", ParameterDirection.Input, SqlDbType.NVarChar, 50, "third");
                addParam(cmd, "@par2", ParameterDirection.Input, SqlDbType.NVarChar, 50, "second");
                addParam(cmd, "@par1", ParameterDirection.Input, SqlDbType.NVarChar, 50, "first");
                addParam(cmd, "@Return", ParameterDirection.ReturnValue, SqlDbType.Int, 0, null);
                conn.Open();
                SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                if (rdr.Read()) Console.WriteLine((string)rdr["Res"]);
                rdr.Close();
                Console.WriteLine("Return value: {0}", cmd.Parameters["@Return"].Value);
            }
            Console.ReadKey();
        }
    }
}

и да, он правильно поддерживает параметры, но я думаю, что это .NET добавляет дополнительные проверки к параметрам, потому что следующий код в Delphi:

procedure TMyClass.Test(Conn: TADOConnection);
var SP:TADOStoredProc;
begin
  SP := TADOStoredProc.Create(nil);
  try
    SP.Connection := Conn;
    SP.ProcedureName := 'paramtest';
    SP.Parameters.CreateParameter('@whatthehell', ftString, pdInput, 50, 'one');
    SP.Parameters.CreateParameter('@AnotherCrap', ftString, pdInput, 50, 'two');
    SP.Parameters.CreateParameter('?', ftString, pdInput, 50, 'three');
    SP.ExecProc;
  finally
    SP.Free;
  end;
end;

возвращает:

@par1 = one; @par2 = two; @par3 = three

и не жалуется на отсутствующие параметры.

pdReturnValue работает, только если этот параметр создается перед любыми другими параметрами.


person Paul    schedule 26.04.2013    source источник


Ответы (1)


Не знаете, какой ответ вы ищете, текст и параметры команды хранимой процедуры передаются драйверу/поставщику или изначально через ADO.NET, который форматирует его как TDS (табличный поток данных) RPC (удаленный вызов процедуры) Сообщение, которое затем передается в сервер, на котором когда-либо используется сетевой протокол; каналы, TCP/IP и др. Данные отправляются в двоичном потоке.

Спецификация TDS доступна от Microsoft, если вы заинтересованы.

SQLCommand Вызовы хранимых процедур нуждаются в имени параметра, его OleDB/ODBC, которые заботятся только о порядке и используют ? в качестве заполнителя параметра, а не @NAME.

Относительно заказа

В вашем примере порядок не имеет значения, потому что вы предоставляете серверу правильные имена для параметров, так что это то, что отправляется на сервер:

exec paramtest @par3=N'third',@par2=N'second',@par1=N'first'

Этой информации достаточно для сервера, чтобы определить правильные параметры/порядок.

Если вы изменили на

addParam(cmd, "@xxpar3",
addParam(cmd, "@xxpar2", 
addParam(cmd, "@xxpar1",

Сервер обнаружит, что у него нет параметра с именем xxxpar*, и выйдет из строя с ошибкой «отсутствует @par1».

Если вы изменили addParam так, чтобы он не устанавливал имена параметров, .net создаст значения по умолчанию:

exec paramtest @Parameter1=N'third',@Parameter2=N'second',@Parameter3=N'first'

Что может вызвать вышеуказанную ошибку.

Если вы изменили addParam так, чтобы он не устанавливал имена параметров, а затем перезаписывал автоматические;

cmd.Parameters.Add(par);
par.ParameterName = "";

Вот что выполняется:

 exec paramtest N'third',N'second',N'first'

в результате чего

 @par1 = third; @par2 = second; @par3 = first

Я понятия не имею, что делает Delphi... Полная версия SQL Server поставляется с инструментом под названием SQL Profiler, который отображает текстовые данные, отправляемые на экземпляр сервера, чтобы вы могли точно видеть, что происходит. Какой профилировщик использовать с sql express?

person Alex K.    schedule 26.04.2013