Выполнение нескольких команд SQL в одном раунде
Я создаю приложение, и я хочу объединить несколько запросов в один раунд в базу данных. Например, можно сказать, что одной странице нужно отобразить список пользователей, список групп и список разрешений.
Итак, я сохранил procs (или просто простые команды sql, такие как "select * from Users" ), и я хочу выполнить три из них. Однако, чтобы заполнить эту страницу, мне нужно совершить 3 круглых поездки.
Теперь я мог бы написать один сохраненный proc ( "getUsersTeamsAndPermissions" ) или выполнить одну команду SQL "select * from Users", exec getTeams, выбрать * из Permissions ".
Но мне было интересно, есть ли лучший способ указать, чтобы сделать 3 операции за один раунд. Преимущества включают в себя более легкое unit test и позволяя движку базы данных parrallelize запросов.
Я использую С# 3.5 и SQL Server 2008.
Ответы
Ответ 1
Единая команда с несколькими частями и параметры хранимой процедуры, которые вы упоминаете, являются двумя параметрами. Вы не можете делать их так, чтобы они "распараллеливались" на db. Тем не менее, оба этих варианта приводят к однократной поездке туда, поэтому вы там хорошо. Невозможно отправить их более эффективно. В sql-сервере 2005 года очень эффективная команда с несколькими параметрами очень эффективна.
Изменить: добавление информации о том, зачем вставлять один вызов.
Хотя вы не хотите слишком беспокоиться о сокращении вызовов, для этого могут быть законные причины.
- Я когда-то был ограничен громоздким драйвером ODBC против мэйнфрейма, и на каждый вызов приходилось 1,2 секунды накладные расходы! Я серьезно. Были времена, когда я переполнял немного лишних звонков. Не красиво.
- Вы также можете оказаться в ситуации, когда вам нужно сконфигурировать ваши SQL-запросы где-то, и вы не можете просто сделать 3 вызова: это должно быть одно. Это не должно быть так, плохой дизайн, но это так. Вы делаете то, что должны делать!
- Иногда, конечно, очень удобно инкапсулировать несколько шагов в хранимой процедуре. Обычно это не для сохранения поездок в оба конца, но для более сложных транзакций, получения идентификатора для новых записей, ограничения для разрешений, обеспечения инкапсуляции, бла-бла-бла. (Но, пожалуйста, не начинайте использовать хранимые процедуры все время.)
Ответ 2
Что-то вроде this. Пример, вероятно, не очень хорош, так как он неправильно распоряжается объектами, но вы получаете эту идею. Здесь очищенная версия:
using (var connection = new SqlConnection(ConnectionString))
using (var command = connection.CreateCommand())
{
connection.Open();
command.CommandText = "select id from test1; select id from test2";
using (var reader = command.ExecuteReader())
{
do
{
while (reader.Read())
{
Console.WriteLine(reader.GetInt32(0));
}
Console.WriteLine("--next command--");
} while (reader.NextResult());
}
}
Ответ 3
Создание одного раунда в три раза будет более эффективным. Вопрос в том, что это стоит того. Все инструменты и рамки ADO.Net и С# 3.5 противодействуют тому, что вы пытаетесь сделать. TableAdapters, Linq2SQL, EF, все это похоже на простую семантику one-call == one-resultset. Таким образом, вы можете потерять некоторую серьезную производительность, пытаясь победить Framework в подчинение.
Я бы сказал, что, если у вас нет серьезных измерений, показывающих, что вам нужно уменьшить количество раундов, воздержитесь. Если вы в конечном итоге требуете этого, используйте хранимую процедуру, чтобы хотя бы дать семантику API.
Но если ваш запрос действительно является тем, что вы опубликовали (т.е. выберите всех пользователей, все команды и все разрешения), то у вас есть obviosuly гораздо больше рыбы, чтобы поджарить, прежде чем уменьшить круговые поездки... сначала уменьшите результаты.
Ответ 4
Мне эта эта ссылка может быть полезна.
Рассмотрите возможность использования, по крайней мере, одного и того же соединения; в соответствии с тем, что он говорит здесь, открытие соединения почти лидирует по производительности в Entity-Framework.
Ответ 5
Создайте временную таблицу? Вставьте все результаты в таблицу temp, а затем select * from @temp-table
как в,
@temptable=....
select @temptable.field=mytable.field from mytable
select @temptable.field2=mytable2.field2 from mytable2
и т.д. Только одна поездка в базу данных, хотя я не уверен, что она на самом деле более эффективна.
Ответ 6
Во-первых, 3 поездки в оба конца не очень важны. Если бы вы говорили о 300 круглых поездках, тогда это было бы другим вопросом, но всего за три раунда я мог бы сделать это, чтобы определить, что это будет преждевременная оптимизация.
Тем не менее, способ, которым я это сделал, вероятно, состоял бы в том, чтобы выполнить 3 сохраненных procuedres, используя SQL:
exec dbo.p_myproc_1 @param_1 = @in_param_1, @param_2 = @in_param_2
exec dbo.p_myproc_2
exec dbo.p_myproc_3
Затем вы можете выполнять итерацию с помощью возвращаемых наборов результатов, как если бы вы выполняли сразу несколько наборов строк.