Выполнение нескольких команд SQL в одном цикле
Я создаю приложение, и я хочу пакетировать несколько запросов в одну поездку туда и обратно в базу данных. Например, допустим, на одной странице должен отображаться список пользователей, список групп и список разрешений.
поэтому я сохранил procs (или просто простые команды sql, такие как "выбрать * от пользователей"), и я хочу выполнить три из них. Однако, чтобы заполнить эту страницу, Я должен сделать 3 поездки туда и обратно.
теперь я мог бы написать один сохраненный proc ("getUsersTeamsAndPermissions") или выполните одну команду SQL"выберите * от пользователей;exec getTeams;выберите * от разрешений".
но мне было интересно, есть ли лучший способ указать, чтобы сделать 3 операции в одной поездке туда и обратно. Преимущества включают в себя упрощение модульного тестирования и возможность парраллелизации запросов компонентом database engine.
Я использую C# 3.5 и SQL Server 2008.
6 ответов
одна команда из нескольких частей и параметры хранимой процедуры, которые вы упомянули, являются двумя вариантами. Вы не можете сделать их таким образом, чтобы они были "распараллелены" на БД. Однако оба этих варианта приводят к одиночная поездка туда и обратно, Так что тут все хорошо. Нет способа отправить их более эффективно. В sql server 2005 и далее очень эффективна команда из нескольких частей, которая полностью параметризована.
редактировать: добавление информации на зачем втискиваться в один звонок.
хотя вы не хотите слишком заботиться о сокращении вызовов, там can быть законные основания для этого.
- однажды я был ограничен вшивым драйвером ODBC против мейнфрейма, и на каждом вызове было 1,2 секунды накладных расходов! Я серьезно. Были времена, когда я немного зубрил extra в моей БД. Не очень.
- вы также можете оказаться в ситуации, когда вам придется настройте свои SQL-запросы где-нибудь, и вы не можете просто сделать 3 вызова: это должен быть один. Это не должно быть так, плохой дизайн, но это. Делай, что должен!
- иногда, конечно, может быть очень хорошо инкапсулировать несколько шагов в хранимой процедуре. Обычно не для сохранения поездок туда и обратно, но для более жестких транзакций, получения ID для новых записей, ограничения разрешений, обеспечения инкапсуляции, бла-бла-бла. (но, пожалуйста, не начинайте использовать сохраненные процедуры все время.)
что-то вроде этой. Пример, вероятно, не очень хорош, поскольку он неправильно распоряжается объектами, но вы получаете идею. Вот очищенная версия:
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());
}
}
сделать один туда и обратно против трех будет более эффективным. Вопрос в том, стоит ли оно того. Весь ADO.Net и набор инструментов и фреймворк C# 3.5 противостоят тому, что вы пытаетесь сделать. TableAdapters, Linq2SQL, EF, все они любят иметь дело с простой семантикой one-call==one-resultset. Таким образом, вы можете потерять серьезную производительность, пытаясь победить фреймворк в подчинении.
Я бы сказал, что если у вас нет серьезных измерений, показывающих, что вам нужно уменьшить количество раундтрипов, воздержитесь. Если ты ... --3-->do в конечном итоге требуется это, а затем используйте хранимую процедуру, чтобы, по крайней мере, дать вид семантики API.
но если ваш запрос действительно то, что вы выложили (т. е. выберите все пользователи все группы и все разрешения), то вы obviosuly есть гораздо больше рыбы, чтобы жарить, прежде чем уменьшить туда и обратно... сокращение первых результатах.
во-первых, 3 туда и обратно не очень большое дело. Если бы вы говорили о 300 туда и обратно, тогда это было бы другое дело, но всего за 3 туда и обратно я бы кондерер это, чтобы определенно быть случаем преждевременной оптимизации.
тем не менее, я бы сделал это, вероятно, для выполнения 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
затем вы можете перебирать возвращенные наборы результатов, как если бы вы напрямую выполняется несколько наборов строк.
создать временную таблицу? Вставьте все результаты в таблицу temp, а затем select * from @temp-table
в,
@temptable=....
select @temptable.field=mytable.field from mytable
select @temptable.field2=mytable2.field2 from mytable2
etc... Только одна поездка в базу данных, хотя я не уверен, что она на самом деле более эффективна.