Выполнить несколько команд SQL в одном цикле - PullRequest
29 голосов
/ 25 февраля 2010

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

Итак, я сохранил procs (или просто простые команды sql, такие как «select * from Users»), и я хочу выполнить три из них. Однако, чтобы заполнить эту страницу, мне нужно совершить 3 поездки в оба конца.

Теперь я могу написать один сохраненный процесс ("getUsersTeamsAndPermissions") или выполнить одну команду SQL "select * from Users; exec getTeams; select * from Permissions".

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

Я использую C # 3.5 и SQL Server 2008.

Ответы [ 6 ]

37 голосов
/ 25 февраля 2010

Что-то вроде этого . Пример, вероятно, не очень хорош, так как он неправильно распределяет объекты, но вы поняли идею. Вот очищенная версия:

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());

    }
}
8 голосов
/ 25 февраля 2010

Одиночная команда, состоящая из нескольких частей, и параметры хранимой процедуры, о которых вы упомянули, являются двумя вариантами. Вы не можете сделать их таким образом, чтобы они были "распараллелены" на БД. Тем не менее, оба эти варианта приводят к одиночному туда и обратно , так что вам там хорошо. Там нет способа отправить их более эффективно. В SQL Server 2005 и более поздних версиях многокомпонентная команда, которая полностью параметризована, очень эффективна.

Редактировать : добавление информации о том, почему втиснуть в один вызов.

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

  • Однажды я был ограничен отвратительным ODBC-драйвером против мэйнфрейма, и на каждый вызов приходилось 1,2 секунды! Я серьезно. Были времена, когда я вливал немного лишних в мои звонки по БД. Не очень.
  • Вы также можете оказаться в ситуации, когда вам нужно где-то настроить свои sql-запросы, и вы не можете просто сделать 3 вызова: это должен быть один. Так не должно быть, плохой дизайн, но это так. Ты делаешь то, что должен!
  • Иногда, конечно, может быть очень хорошо заключить несколько шагов в хранимую процедуру. Обычно не для сохранения циклов, а для более жестких транзакций, получения идентификатора для новых записей, ограничения для разрешений, обеспечения инкапсуляции, бла-бла-бла. ( Но, пожалуйста, не начинайте использовать хранимые процедуры все время. )
2 голосов
/ 25 февраля 2010

Создание одного туда-обратно против трех будет действительно более эффективным. Вопрос в том, стоит ли беспокоиться. Весь набор инструментов и фреймворков ADO.Net и C # 3.5 противостоят тому, что вы пытаетесь сделать. TableAdapters, Linq2SQL, EF, все они любят иметь дело с простой семантикой одного вызова == одного результата. Таким образом, вы можете потерять некоторую серьезную производительность, пытаясь превратить Framework в представление.

Я бы сказал, что если у вас нет каких-либо серьезных измерений, показывающих, что вам нужно уменьшить количество поездок туда и обратно, воздержитесь. Если вы делаете , в конце концов, требуется это, то используйте хранимую процедуру, чтобы хотя бы дать семантику API-типа.

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

1 голос
/ 30 ноября 2010

Я эта ссылка может быть полезной.

Подумайте об использовании хотя бы того же открытия соединения; в соответствии с тем, что здесь написано здесь , открытие соединения является едва ли не лидером по производительности в Entity-Framework.

0 голосов
/ 25 февраля 2010

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

Тем не менее, я бы, вероятно, выполнил бы 3 хранимых процесса с помощью 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

Затем можно выполнить итерацию по возвращенным наборам результатов, как если бы вы непосредственно выполнили несколько наборов строк.

0 голосов
/ 25 февраля 2010

Создать временную таблицу? Вставьте все результаты в временную таблицу и затем select * from @temp-table

как в,

@temptable=....
select @temptable.field=mytable.field from mytable
select @temptable.field2=mytable2.field2 from mytable2

и т.д ... Только одна поездка в базу данных, хотя я не уверен, что она на самом деле более эффективна.

...