GO Po każdej instrukcji T-SQL

34

Jakie jest uzasadnienie używania instrukcji GO po każdej instrukcji SQL? Rozumiem, że GO sygnalizuje koniec partii i / lub zezwala na reputację wyciągów, ale jaką korzyść ma przy ich użyciu po każdym wyciągu.

Jestem ciekawy, ponieważ wiele dokumentów Microsoft itp. Zaczęło z nich korzystać po każdym stwierdzeniu, a może dopiero zacząłem to zauważać.

Co również uważa się za najlepszą praktykę?

Idiota
źródło

Odpowiedzi:

51

Przed odpowiedzią, kiedy i dlaczego go użyć, najważniejsze GOjest, aby dokładnie zrozumieć, co jest, a co nie.

GOSłowo kluczowe jest używane przez SQL Server Management Studio i SQLCMD w celu oznaczenia jednej rzeczy i tylko jednej rzeczy: końca zestawu instrukcji. W rzeczywistości możesz nawet zmienić to, czego używasz do kończenia partii na coś innego niż „GO”:

wprowadź opis zdjęcia tutaj

Powyższy zrzut ekranu jest konfigurowalną opcją w ramach SSMS.

Ale co to jest partia? To odniesienie do BOL mówi najlepiej:

Partia to grupa co najmniej jednej instrukcji Transact-SQL wysłanej w tym samym czasie z aplikacji do programu SQL Server w celu wykonania.

Proste. Jest to po prostu niestandardowy sposób, w jaki aplikacja (tak ... aplikacja) wysyła instrukcje do programu SQL Server. Zobaczmy przykład tego wyglądający na aplikację. Użyję programu PowerShell, aby naśladować działanie aplikacji w celu wysyłania instrukcji i partii do programu 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
}

Komentarze zdradzają, ale widać powyżej, że programowo wysyłamy dwie partie do SQL Server. Sprawdźmy to jednak. Moim wyborem jest skorzystanie z Rozszerzonych zdarzeń:

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

Sesja XEvent polega wyłącznie na przechwytywaniu instrukcji i partii, które rozpoczynają się i kończą z aplikacji o nazwie "BatchTesting"(jeśli zauważysz mój ciąg połączenia w moim przykładzie kodu PowerShell, jest to szybki sposób na sprawdzenie konkretnego inicjatora zdarzeń za pomocą „aplikacji” nazwa ”parametr ciągu połączenia i odfiltrowanie tego).

Po uruchomieniu kodu programu PowerShell w celu wysłania tych partii i instrukcji widzę następujące wyniki:

wprowadź opis zdjęcia tutaj

Jak widać na zrzucie ekranu, jasne jest, w jaki sposób zestawienia dzielą się na dwie różne partie, co jest również widoczne za pomocą środków, które nazywaliśmy partiami. A jeśli spojrzymy batch_textna pierwsze wystąpienie sql_batch_starting, możemy zobaczyć wszystkie instrukcje zawarte w tej partii:

    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;

Z tym wyjaśnieniem, co to jest partia, teraz pojawia się odpowiedź na pytanie, kiedy należy kończyć partie. Reguły dotyczące partii znajdują się w tym dokumencie referencyjnym BOL dotyczącym partii :

UTWÓRZ DOMYŚLNE, UTWÓRZ FUNKCJĘ, UTWÓRZ PROCEDURĘ, UTWÓRZ ZASADĘ, UTWÓRZ SCHEMAT, UTWÓRZ TRIGGER i UTWÓRZ instrukcje nie mogą być łączone z innymi instrukcjami w partii. Instrukcja CREATE musi rozpocząć partię. Wszystkie pozostałe instrukcje, które następują w tej partii, będą interpretowane jako część definicji pierwszej instrukcji CREATE.

Tabeli nie można zmienić, a następnie do nowych kolumn, do których odwołuje się ta sama partia.

Jeśli instrukcja EXECUTE jest pierwszą instrukcją w partii, słowo kluczowe EXECUTE nie jest wymagane. Słowo kluczowe EXECUTE jest wymagane, jeśli instrukcja EXECUTE nie jest pierwszą instrukcją w partii.

Podobnie, niektóre błędy w czasie wykonywania (błędy kompilacji nie pozwalają na uruchomienie wykonywania wsadu), które występują podczas wsadu, mogą powodować różne zachowania: całkowite przerwanie wsadu lub kontynuowanie wsadu i tylko przerwanie instrukcji naruszającej prawo (powyższe link podaje dwa naprawdę dobre przykłady: na przykład błąd przepełnienia arytmetycznego zatrzyma wykonanie partii, podczas gdy błąd naruszenia ograniczenia uniemożliwi tylko wykonanie bieżącej instrukcji, ale partia będzie kontynuowana).

Podobnie jak wiele innych rzeczy w naszym zawodzie, osobiste preferencje będą ogromną siłą napędową stojącą za tym, jak Ty jako osoba i autor kodu T-SQL kończysz partie. Niektóre osoby jawnie definiują partie tylko wtedy, gdy są absolutnie konieczne (te wymagania powyżej), a inne kończą partie programowo w 100% przypadków , nawet jeśli wykonują tylko jedną instrukcję w oknie zapytania w SSMS. Większość ludzi zwykle spada gdzieś pośrodku tych dwóch granic. Pod względem wartości terminatory instrukcji mają to samo, a także bardzo niewiele wymuszonych wymagań. Dużą część tego wszystkiego stanowi styl kodu , w którym nie jest on wymuszany (w SSMS i SQLCMD).

Thomas Stringer
źródło
Być może naiwny komentarz, ale uderza mnie, że SQL Server mógł sam ustalić, co uruchomić w partiach (w taki sam sposób, w jaki silnik bazy danych obsługuje wiele innych optymalizacji). Np. Używając reguł, które opisałeś, zamiast polegać na skrypcie, który może być podatny na błędy i może powodować niepotrzebne wzdęcia w skryptach.
Steve Chambers
1
@ SteveChambers dokładnie mój sentyment. Odpowiedź brzmi „to takie proste” (partia jest grupą jednej lub więcej instrukcji Transact-SQL wysłanych w tym samym czasie z aplikacji do SQL Server w celu wykonania.) Ale tak nie jest. Istnieją kombinacje instrukcji, które mógłbym spróbować wysłać partią, która kończy się niepowodzeniem. Ostatecznie myślę, że musisz zrozumieć, dlaczego i jak wysyłać partię różni się od wysyłania zestawu pojedynczych instrukcji - więc w końcu udzieliłem własnej odpowiedzi na ten temat: stackoverflow.com/a/56370223/3714936 - który również przemawia do twojego komentarza .
youcantryreachingme