Плюсы и минусы использования SqlCommand Подготовка в С#?

Когда я читал книги, чтобы изучить С# (может быть, некоторые старые книги Visual Studio 2005), я столкнулся с советами всегда использовать SqlCommand.Prepare каждый раз, когда я выполняю SQL-вызов (независимо от того, является ли его 'a SELECT/UPDATE или INSERT в SQL Server 2005/2008), и я передаю ему параметры. Но действительно ли это?

  • Следует ли это делать каждый раз? Или просто иногда?

  • Имеет ли значение, передается ли один параметр или пять или двадцать?

  • Какой толчок он должен дать, если таковой имеется? Было бы заметно вообще (я использовал SqlCommand.Prepare здесь и пропустил его там, и у меня не было никаких проблем или заметных различий).

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

public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) {
    const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni,  @varStopaOdniesienia) AS 'Benchmark'";
    using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) {
    using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) {
        sqlQuery.Prepare();
        sqlQuery.Parameters.AddWithValue("@varPortfelID", varPortfelID);
        sqlQuery.Parameters.AddWithValue("@varStopaOdniesienia", varStopaOdniesienia);
        sqlQuery.Parameters.AddWithValue("@data", data);
        sqlQuery.Parameters.AddWithValue("@varBenchmarkPoprzedni", varBenchmarkPoprzedni);
        using (var sqlQueryResult = sqlQuery.ExecuteReader())
            if (sqlQueryResult != null) {
                while (sqlQueryResult.Read()) {

                }
            }
    }
}

Дополнительные пояснения:

Если я перемещаю sqlQuery.Prepare(), как в коде ниже, возникает исключение, что размер должен быть явно объявлен, что в основном приводит меня к мысли, что иметь sqlQuery.Prepare(), как первый, делает его бесполезным? Может ли кто-нибудь показать правильное использование, используя мой пример?

public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) {
    const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni,  @varStopaOdniesienia) AS 'Benchmark'";
    using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) {
    using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) {

        sqlQuery.Parameters.AddWithValue("@varPortfelID", varPortfelID);
        sqlQuery.Parameters.AddWithValue("@varStopaOdniesienia", varStopaOdniesienia);
        sqlQuery.Parameters.AddWithValue("@data", data);
        sqlQuery.Parameters.AddWithValue("@varBenchmarkPoprzedni", varBenchmarkPoprzedni);
        sqlQuery.Prepare();
        using (var sqlQueryResult = sqlQuery.ExecuteReader())
            if (sqlQueryResult != null) {
                while (sqlQueryResult.Read()) {

                }
            }
    }
}

Как мне это сделать? Добавляя .size рядом с параметрами и выполняя varPortfel.Lenght, если это строка и т.д.?

Ответ 1

В документации MSDN:

"Перед тем, как позвонить в Prepare, укажите тип данных каждого параметра в выражение должно быть подготовлено. Для каждого параметр, который имеет переменную длину тип данных, вы должны установить размер для максимального размера. Подготовка возвращает ошибку, если эти условия не выполняются.

Если вы вызываете метод Execute после вызов Prepare, любое значение параметра что больше, чем значение заданное свойством Size автоматически усекается до первоначальный заданный размер параметр и отсутствие ошибок усечения возвращаются.

Параметры вывода (независимо от того, не) должны иметь пользовательские данные тип. Если вы укажете переменную длину тип данных, вы также должны указать максимальный размер."

Кроме того, "Если CommandType свойство установлено в TableDirect, Подготовка не делает ничего. Если CommandType установлен на StoredProcedure, вызов Подготовка должна быть успешной,..."

Это обычно используется, чтобы убедиться, что конечный пользователь не использует технику SQL Injection для добавления или удаления информации, которую вы также не хотите использовать в базе данных.

Я просмотрел его и просмотрел эту статью http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.prepare.aspx. Ваша проблема заключается в том, что вам необходимо определить свои параметры перед запуском .Prepare(), а затем установить параметры после запуска .Prepare(). Прямо сейчас вы делаете оба раньше. Я бы попробовал что-то вроде этого (примечание, которое я не тестировал, поэтому мой синтаксис может быть немного выключен).

public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) {
    const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni,  @varStopaOdniesienia) AS 'Benchmark'";
    using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) {
    using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) {

        sqlQuery.Parameters.Add("@varPortfelID");
        sqlQuery.Parameters.Add("@varStopaOdniesienia");
        sqlQuery.Parameters.Add("@data");
        sqlQuery.Parameters.Add("@varBenchmarkPoprzedni");

        sqlQuery.Prepare();
        sqlQuery.ExecuteNonQuery();//This might need to be ExecuteReader()

        sqlQuery.Parameters[0].Value = varPortfelID;
        sqlQuery.Parameters[1].Value = varStopaOdniesienia;
        sqlQuery.Parameters[2].Value = data;
        sqlQuery.Parameters[3].Value = varBenchmarkPoprzedni;

        using (var sqlQueryResult = sqlQuery.ExecuteReader())
            if (sqlQueryResult != null) {
                while (sqlQueryResult.Read()) {

                }
            }
    }
}

Ответ 2

Другим преимуществом является то, что при этом план SQL-запросов компилируется, кэшируется и повторно используется. Это не имеет большого значения, если для небольшого количества вызовов к вашему запросу, но если у вас есть много, на самом деле есть некоторые существенные преимущества в производительности.

Ответ 3

Из моего собственного опыта: повышение производительности очень важно. Некоторое время назад я работал над проектом, в котором мы использовали наше собственное объектно-реляционное сопоставление. Мы использовали огромную базу данных в качестве постоянного хранилища сложной объектной модели - с загрузкой объекта по требованию и временем жизни объекта с ограниченными возможностями.

Использование подготовленных команд имело решающее значение для успеха этого приложения, поскольку оно само по себе фактически использовало систему.

Другими словами: если вы выполняете многие команды SQL, которые точно такие же или отличаются только значениями параметров, вы увидите огромный прирост производительности.

У меня нет точных цифр или ссылок, но я могу подтвердить свой собственный опыт.