Выполнить несколько хранимых процедур с одной поездкой в ​​базу данных - PullRequest
1 голос
/ 20 мая 2011

У меня много устаревших кодов доступа к данным, в основном SqlCommand с вызовами хранимых процедур, которые мы использовали для выполнения большого количества вставки статистики в базу данных. Пока сервер SQL находился на том же компьютере, что и приложение, производительность была приемлемой, но сейчас мы пытаемся переместить некоторые данные в SQL Azure.

Проблема в том, что наш код вызывает SP для каждой записи для вставки, что приводит к довольно большим числам поездок в базу данных, и, если они не расположены на одном сервере, это занимает некоторое время.

var conn = new SqlConnection("connString")
var cmd = new SqlCommand(conn, "spMyStoreProc");
cmd.Params.Add("@a", SqlDbType.VarChar, 10);
cmd.Params.Add("@b", SqlDbType.Int);

using(conn)
{
 conn.Open();
 foreach(var rec in recordsToInsert)
 {
   cmd.Parameters["@a"].Value = rec.A;
   cmd.Parameters["@b"].Value = rec.B;
   cmd.ExecuteNonQuery();
 }
 conn.Close();
}

Я пробовал приведенный выше код с транзакциями и без них.

Я также пытался использовать «пакетный» оператор SQL для выполнения нескольких SP в каждой поездке на сервер. Как это:

var cmd = new SqlCommand(conn);
cmd.CommandText = "EXEC spMyStoreProc @a='a' @b=2; EXEC spMyStoreProc @a='b' @b=4;"

Это значительно повышает производительность операции, но, поскольку у меня довольно много SP, где каждый SP имеет около 20-50 параметров, довольно утомительно писать этот код для всех команд вставки в этом компоненте доступа к данным.

Это лучший способ добиться этого, или я могу как-то сказать ADO.NET, что я хочу выполнять свои вызовы в пакетном режиме (не ищите ничего, что подсказывает, что это возможно, но я чувствую, что по крайней мере должен спросить), чтобы избежать задержки в сети и т. Д. каждый вызов SP?

Если нет, то кто-нибудь знает какой-либо хороший способ добиться этого без необходимости писать его «от руки», и, поскольку это унаследованное приложение, я не могу полностью изменить уровень данных. Существуют ли приложения, которые могут принимать SqlCommands с параметрами и генерировать TQL, который они будут выполнять?

Заранее спасибо

Ответы [ 2 ]

2 голосов
/ 20 мая 2011

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


CREATE PROCEDURE sp_RunBatch(@param1, @param2, etc [all the parameters you need])
AS

exec spMyStoreProc @a='a'
exec spMyStoreProc2 @b='b' 


Преимуществами этого является множество, некоторые из которых заключаются в том, что все они централизованы, и вы можете даже обернуть их все в транзакцию, чтобы не делать грязных вставок (учитывая, что все они зависят друг от друга).

Кроме того, если вы не хотите передавать параметры 20/30 каждому SP, вы можете захотеть создать тип данных, определяемый пользовательской таблицей, для каждого набора параметров, который вы можете передать.Таким образом, каждый SP получает 1 или 2 параметра, и код становится намного проще и удобочитаемее.

РЕДАКТИРОВАТЬ:

Это хороший справочник для пользовательских типов таблиц: http://msdn.microsoft.com/en-us/library/bb675163.aspx

А вот как передать табличные типы на сервер SQL: http://msdn.microsoft.com/en-us/library/bb675163.aspx

0 голосов
/ 20 мая 2011

Альтернативой подходу MR будет отправка всех ваших параметров в виде XML-документа, а затем синтаксический анализ XML-документа для извлечения ваших параметров.Это может немного упростить интерфейс.

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

Таким образом, у вас будетцикл выглядит следующим образом, и вы бы вызвали новый метод расширения ToInlineSql:

string sqlCommand = "";
foreach(var rec in recordsToInsert) 
{   cmd.Parameters["@a"].Value = rec.A;   
    cmd.Parameters["@b"].Value = rec.B;
    sqlCommand += cmd.ToInlineSql(); 
}
// execute sqlCommand 

Метод расширения ToInlineSql может выглядеть следующим образом (peuso-код, вам нужно будет добавить определенные вещи, такие как проверка длятип данных и т. д.) [и вот ссылка на sp_executesql :

public static class SqlCmdExt 
{
      public static string ToInlineSql(this SqlCommand cmd)
      {
            string sql = "sp_executesql " + cmd.CommandText  ;
            foreach (SqlParameter p in cmd.Parameters)
            {
                  sql += ", @" + p.Name + " " + p.DataType.ToString() ;
                  sql += ", " + p.Name + " = " + p.Value;
            }
            sql += ";";
            return sql;
      }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...