GO После каждого оператора T-SQL

34

Какова причина использования оператора GO после каждого оператора SQL? Я понимаю, что GO сигнализирует об окончании партии и / или разрешает репутацию утверждений, но какое преимущество имеет его использование после каждого утверждения.

Мне просто любопытно, как много документации Microsoft и т. Д. Начали использовать ее после каждого утверждения, или, может быть, я только начал замечать.

И что считается лучшей практикой?

TheIdiot
источник

Ответы:

51

Прежде чем ответить, когда его использовать и почему, сначала необходимо понять, что именно GO, а что нет.

Ключевое слово GOиспользуется SQL Server Management Studio и SQLCMD для обозначения одного и только одного: конца пакета утверждений. Фактически, вы можете даже изменить то, что вы используете для завершения пакетов, на что-то другое, кроме «GO»:

введите описание изображения здесь

Этот скриншот выше - опция в SSMS, которая настраивается.

Но что такое партия? Эта ссылка BOL говорит это лучше всего:

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

Просто как тот. Это просто пользовательский способ, которым приложение (да ... приложение) отправляет операторы в SQL Server. Давайте посмотрим на пример приложения этого вида. Я буду использовать PowerShell для имитации того, что приложение будет делать для отправки операторов и пакетов на SQL Server:

$ConnectionString = "data source = SomeSQLInstance; initial catalog = AdventureWorks2012; trusted_connection = true; application name = BatchTesting;"

try {
    $SqlConnection = New-Object System.Data.SqlClient.SqlConnection($ConnectionString)
    $SqlCmd = New-Object System.Data.SqlClient.SqlCommand
    $SqlCmd.Connection = $SqlConnection

    # first batch of statements
    #
    $SqlCmd.CommandText = "
        select * from humanresources.department where departmentid = 1;
        select * from humanresources.department where departmentid = 2;
        select * from humanresources.department where departmentid = 3;
        select * from humanresources.department where departmentid = 4;"

    # execute the first batch
    #
    $SqlConnection.Open()
    $SqlCmd.ExecuteNonQuery()
    $SqlConnection.Close()

    # second batch of statements
    #
    $SqlCmd.CommandText = "
        select * from humanresources.department where departmentid = 5;
        select * from humanresources.department where departmentid = 6;
        select * from humanresources.department where departmentid = 7;
        select * from humanresources.department where departmentid = 8;"

    # execute the second batch
    #
    $SqlConnection.Open()
    $SqlCmd.ExecuteNonQuery()
    $SqlConnection.Close()
}
catch {
    $SqlCmd.Dispose()
    $SqlConnection.Dispose()
    Write-Error $_.Exception
}

Комментарии выдают это, но вы можете видеть выше, что мы программно отправляем две партии SQL Server. Давайте проверим это, хотя. Мой выбор здесь - использовать расширенные события:

create event session BatchTesting
on server
add event sqlserver.sql_batch_starting
(
    set
        collect_batch_text = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
),
add event sqlserver.sql_batch_completed
(
    set
        collect_batch_text = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
),
add event sqlserver.sql_statement_starting
(
    set
        collect_statement = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
),
add event sqlserver.sql_statement_completed
(
    set
        collect_statement = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
)
add target package0.event_file
(
    set
        filename = N'<MyXelLocation>\BatchTesting.xel'
);
go

alter event session BatchTesting
on server
state = start;
go

Все, что делает этот сеанс XEvents, - это захват операторов и пакетов, которые запускаются и завершаются из приложения с именем "BatchTesting"(если вы заметили мою строку подключения в моем примере кода PowerShell, это быстрый способ взглянуть на конкретного источника событий с помощью приложения "" имя "параметр строки подключения и отфильтровывание этого).

После выполнения кода PowerShell для отправки этих пакетов и операторов я вижу следующие результаты:

введите описание изображения здесь

Как вы можете видеть на скриншоте, ясно, как операторы делятся на две разные партии, что также очевидно по средствам, которые мы использовали для вызова пакетов. И если мы посмотрим на batch_textпервое вхождение sql_batch_starting, мы можем увидеть все операторы, включенные в этот пакет:

    select * from humanresources.department where departmentid = 1;
    select * from humanresources.department where departmentid = 2;
    select * from humanresources.department where departmentid = 3;
    select * from humanresources.department where departmentid = 4;

С этим объяснением того, что такое партия, теперь приходит ответ на ваш вопрос о том, когда прекратить партии. Правила для партий находятся на этой ссылке BOL относительно партий :

Операторы CREATE DEFAULT, CREATE FUNCTION, CREATE PROCEDURE, CREATE RULE, CREATE SCHEMA, CREATE TRIGGER и CREATE VIEW нельзя объединять с другими операторами в пакете. Оператор CREATE должен запустить пакет. Все остальные операторы, которые следуют в этом пакете, будут интерпретированы как часть определения первого оператора CREATE.

Таблица не может быть изменена, а затем новые столбцы, на которые есть ссылки в том же пакете.

Если оператор EXECUTE является первым оператором в пакете, ключевое слово EXECUTE не требуется. Ключевое слово EXECUTE необходимо, если оператор EXECUTE не является первым оператором в пакете.

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

Как и многие вещи в нашей профессии, личные предпочтения будут огромной движущей силой того, как вы, как человек и автор кода T-SQL, завершаете пакеты. Некоторые люди явно определяют пакеты только тогда, когда они абсолютно необходимы (см. Выше для этих требований), а другие завершают пакеты программно 100% времени , даже когда они выполняют только один оператор в окне запросов в SSMS. Большинство людей обычно попадают где-то посередине этих двух границ. Что бы ни стоило, терминаторы операторов имеют то же самое следование с очень небольшим количеством обязательных требований. Большая часть всего этого - стиль кода , где он не применяется (в SSMS и SQLCMD).

Томас Стрингер
источник
Возможно, наивный комментарий, но мне кажется, что SQL Server мог сам определить, что запускать в пакетах (так же, как многие другие оптимизации обрабатываются ядром базы данных). Например, используя правила, которые вы описали, вместо того, чтобы полагаться на пользователя в сценарии, который может быть подвержен ошибкам и, кажется, добавляет ненужные раздувания в сценарии.
Стив Чемберс
1
@SteveChambers мои чувства точно. Ответ гласит: «это так просто» (пакет представляет собой группу из одного или нескольких операторов Transact-SQL, одновременно отправляемых из приложения в SQL Server для выполнения.) Но это не так. Существуют комбинации утверждений, которые я могу попытаться отправить в пакете, но не получится. В конце концов , я думаю , что вы должны понять , почему и как отправка партии отличается от отправки набора индивидуальных заявлений - так что я , наконец , способствовал мой собственный ответ на это: stackoverflow.com/a/56370223/3714936 - что также говорит на ваш комментарий ,
youcantryreachingme