IR después de cada instrucción T-SQL

34

¿Cuál es el razonamiento detrás del uso de la instrucción GO después de cada instrucción SQL? Entiendo que GO señala el final del lote y / o permite la reputación de las declaraciones, pero qué ventaja tiene usarlo después de cada declaración.

Tengo curiosidad porque una gran cantidad de documentación de Microsoft, etc., comenzó a usarla después de cada declaración o tal vez comencé a notarlo.

Además, ¿qué se considera mejor práctica?

El idiota
fuente

Respuestas:

51

Antes de responder cuándo usarlo y por qué, es primordial comprender exactamente qué GOes y qué no es.

GOSQL Server Management Studio y SQLCMD utilizan la palabra clave para indicar una cosa y solo una: el final de un lote de instrucciones. De hecho, incluso puede cambiar lo que usa para terminar los lotes a algo que no sea "IR":

ingrese la descripción de la imagen aquí

La captura de pantalla anterior es una opción dentro de SSMS que es configurable.

Pero, ¿qué es un lote? Esta referencia de BOL lo dice mejor:

Un lote es un grupo de una o más instrucciones Transact-SQL enviadas al mismo tiempo desde una aplicación a SQL Server para su ejecución.

Simple como eso. Es solo una forma personalizada de que una aplicación (sí ... una aplicación) envíe declaraciones a SQL Server. Veamos un ejemplo de esto que parece una aplicación. Usaré PowerShell para imitar lo que haría una aplicación para enviar declaraciones y lotes a 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
}

Los comentarios lo delatan, pero puede ver arriba que enviamos dos lotes a SQL Server mediante programación. Sin embargo, verifiquemos eso. Mi elección aquí es usar eventos extendidos:

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

Todo lo que está haciendo esta sesión de XEvents es capturar las declaraciones y los lotes que comienzan y se completan desde una aplicación llamada "BatchTesting"(si observa mi cadena de conexión en mi ejemplo de código de PowerShell, es una forma rápida de ver un creador de eventos en particular usando la aplicación " nombre "parámetro de cadena de conexión y filtrado de eso).

Después de ejecutar el código de PowerShell para enviar esos lotes y declaraciones, veo los siguientes resultados:

ingrese la descripción de la imagen aquí

Como puede ver en la captura de pantalla, está claro cómo las declaraciones se dividen en dos lotes diferentes, también evidente por los medios que solíamos llamar los lotes. Y si observamos batch_textla primera aparición de sql_batch_starting, podemos ver todas las declaraciones incluidas en ese lote:

    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;

Con esa explicación de qué es un lote, ahora viene la respuesta a su pregunta de cuándo terminar los lotes. Las reglas para los lotes se encuentran en esta referencia de BOL con respecto a los lotes :

Las declaraciones CREATE DEFAULT, CREATE FUNCTION, CREATE PROCEDURE, CREATE RULE, CREATE SCHEMA, CREATE TRIGGER y CREATE VIEW no se pueden combinar con otras declaraciones en un lote. La instrucción CREATE debe iniciar el lote. Todas las demás declaraciones que siguen en ese lote se interpretarán como parte de la definición de la primera instrucción CREATE.

No se puede cambiar una tabla y luego las nuevas columnas a las que se hace referencia en el mismo lote.

Si una instrucción EXECUTE es la primera instrucción en un lote, la palabra clave EXECUTE no es necesaria. La palabra clave EXECUTE es necesaria si la instrucción EXECUTE no es la primera instrucción del lote.

Del mismo modo, ciertos errores de tiempo de ejecución (los errores de compilación no permitirán que se inicie la ejecución de un lote) que ocurren durante un lote pueden causar diferentes comportamientos: abortar el lote por completo o continuar el lote y solo abortar la declaración ofensiva (lo anterior El enlace proporciona dos ejemplos realmente buenos: un error de desbordamiento aritmético, por ejemplo, detendrá la ejecución del lote, mientras que un error de violación de restricción solo evitará que la declaración actual se complete pero el lote continuará ejecutándose).

Sin embargo, como muchas cosas en nuestra profesión, la preferencia personal será una gran fuerza impulsora detrás de cómo usted, como individuo y escritor de código T-SQL, termina los lotes. Algunas personas solo definen explícitamente lotes cuando tienen que hacerlo (ver arriba para esos requisitos), y otros terminan los lotes programáticamente el 100% del tiempo , incluso cuando solo están ejecutando una sola declaración en una Ventana de consulta en SSMS. La mayoría de las personas suelen caer en algún lugar en el medio de esos dos límites. Para lo que vale, los terminadores de declaraciones tienen el mismo seguimiento con muy pocos requisitos obligatorios. Una gran parte de todo esto es el estilo de código , donde no se aplica (en SSMS y SQLCMD).

Thomas Stringer
fuente
Tal vez sea un comentario ingenuo, pero me parece que SQL Server podría haber determinado qué ejecutar en lotes (de la misma manera que el motor de la base de datos maneja muchas otras optimizaciones). Por ejemplo, usar las reglas que ha descrito en lugar de confiar en que el usuario las escriba, lo que puede ser propenso a errores y parece agregar una hinchazón innecesaria a las secuencias de comandos.
Steve Chambers
1
@SteveChambers mi sentimiento exactamente. La respuesta dice "es tan simple como eso" (un lote es un grupo de una o más instrucciones Transact-SQL enviadas al mismo tiempo desde una aplicación a SQL Server para su ejecución). Pero no lo es. Hay combinaciones de declaraciones que podría intentar y enviar en un lote que falla. En última instancia, creo que debe comprender por qué y cómo enviar un lote es diferente de enviar un conjunto de declaraciones individuales, por lo que finalmente aporté mi propia respuesta en esta: stackoverflow.com/a/56370223/3714936 , que también habla de su comentario .
youcantryreachingme