Qu'est-ce qu'un «lot» et pourquoi GO est-il utilisé?

134

J'ai lu et lu sur MSDN, etc. Ok, donc ça signale la fin d'un lot.

Qu'est-ce qui définit un lot? Je ne vois pas pourquoi je dois y aller quand je colle un tas de scripts à exécuter tous en même temps.

Je n'ai jamais compris GO. Quelqu'un peut-il mieux expliquer cela et quand je dois l'utiliser (après combien ou quel type de transactions)?

Par exemple, pourquoi aurais-je besoin de GO après chaque mise à jour ici:

 UPDATE [Country]
   SET [CountryCode] = 'IL'
 WHERE code = 'IL'

 GO

 UPDATE [Country]
   SET [CountryCode] = 'PT'
 WHERE code = 'PT'
PositiveGuy
la source
FWIW, il semble que un goréinitialise / efface également declare @fooles déclarations de variables - je devais obtenir que vous deviez déclarer des erreurs @foo , jusqu'à ce que je commente le go.
JL Peyret

Réponses:

107

GOn'est pas correctement une commande TSQL.

Au lieu de cela, c'est une commande au programme client spécifique qui se connecte à un serveur SQL (Sybase ou Microsoft - pas sûr de ce que fait Oracle), signalant au programme client que l'ensemble des commandes qui y ont été entrées jusqu'à ce que le "go" ait besoin à envoyer au serveur pour être exécuté.

Pourquoi / quand en avez-vous besoin?

  • GO dans le serveur MS SQL a un paramètre "count" - vous pouvez donc l'utiliser comme un raccourci "répéter N fois".

  • Des mises à jour extrêmement volumineuses peuvent remplir le journal du serveur SQL. Pour éviter cela, il peut être nécessaire de les séparer en lots plus petits via go.

    Dans votre exemple, si la mise à jour d'un ensemble de codes de pays a un volume tel qu'il manquera d'espace de journal, la solution consiste à séparer chaque code de pays en une transaction distincte - ce qui peut être fait en les séparant sur le client avec go.

  • Certaines instructions SQL DOIVENT être séparées par GO des suivantes pour fonctionner.

    Par exemple, vous ne pouvez pas supprimer une table et recréer la table du même nom en une seule transaction, au moins dans Sybase (idem pour la création de procédures / triggers):

> drop table tempdb.guest.x1          
> create table tempdb.guest.x1 (a int)
> go
  Msg 2714, Level 16, State 1
  Server 'SYBDEV', Line 2
  There is already an object named 'x1' in the database.   
  
> drop table tempdb.guest.x1          
> go
> create table tempdb.guest.x1 (a int)
> go
>
DVK
la source
4
L'instruction GO ne crée pas de transaction. Si vous incluez plusieurs instructions GO dans une instruction BEGIN TRANSACTION et que vous ferez finalement un ROLLBACK, cela annulera tous les GO. Et si dans un GO au milieu vous obtiendrez une erreur, et à la fin vous ferez COMMIT, tous GO sans erreur seront validés. C'est un peu délicat.
TZ
7
GOne "crée pas de transaction pour vous". Si vous ne lancez pas une transaction explicite, chaque instruction créera de toute façon sa propre transaction. C'est complètement orthogonal. Si vous souhaitez diviser une mise à jour plus importante en étapes plus petites, vous pouvez toujours le faire en un seul lot comme dans le WHILE @@ROWCOUNT > 0modèle commun .
Martin Smith
3
Si vous ne lancez pas une transaction explicite, UPDATE T1 SET X =2;UPDATE T1 SET X =2;elle s'exécutera de toute façon comme deux transactions distinctes . L'ajout de ne GOfait absolument aucune différence. Et même , si vous êtes en cours d' exécution dans une transaction explicite , il couvre des lots et encore ne GO fait aucune différence.
Martin Smith
4
Tout comme une clarification pour quiconque lira ceci plus tard ... GOn'a absolument rien à voir avec les transactions, et rend les réponses au deuxième point sur les transactions et la taille d'un fichier journal incorrecte. GOn'aura aucun effet. Les première et troisième réponses sont correctes. De plus, vous devez parfois séparer les instructions en lots séparés, par exemple vous ne pouvez pas ajouter une colonne à une table, puis utiliser cette colonne plus tard dans le même lot. (suite)
Robert McKee
4
De plus, étant donné que certaines erreurs annulent un lot (certaines erreurs n'interrompent qu'une instruction), elles jouent également un rôle dans la détection et la récupération des erreurs. Et certaines instructions ( CREATE VIEW, etc.) doivent être dans leur propre lot.
Robert McKee
26

GO n'est pas une déclaration, c'est un séparateur de lots.

Les blocs séparés par GOsont envoyés par le client au serveur pour traitement et le client attend leurs résultats.

Par exemple, si vous écrivez

DELETE FROM a
DELETE FROM b
DELETE FROM c

, cela sera envoyé au serveur sous forme de 3requête sur une seule ligne.

Si vous écrivez

DELETE FROM a
GO
DELETE FROM b
GO
DELETE FROM c

, cela sera envoyé au serveur sous forme de 3requêtes sur une ligne.

GOlui-même ne va pas au serveur (sans jeu de mots). C'est un mot réservé pur côté client et n'est reconnu que par SSMSet osql.

Si vous utilisez un outil de requête personnalisé pour l'envoyer via la connexion, le serveur ne le reconnaîtra même pas et émettra une erreur.

Quassnoi
la source
4
Pourquoi avez-vous du tout à faire des lots?
PositiveGuy
3
Donc, GO signifie l'envoyer, puis n'exécutez pas le lot suivant jusqu'à ce que le client reçoive "OK, ce lot est terminé et a réussi", c'est essentiellement ce que fait le GO pour que le prochain lot puisse être exécuté avec succès et que le client le sache assurez-vous que le lot avant qu'il ne soit fait côté serveur.
PositiveGuy
3
@coffeeaddict: en gros, oui. De plus, certaines instructions doivent être les premières de leurs lots (comme CREATE SCHEMA); les autres exigent d'être les seules déclarations dans leurs lots (comme SET SHOWPLAN_XML ON)
Quassnoi
19

De nombreuses commandes doivent être dans leur propre lot, comme CREATE PROCEDURE

Ou, si vous ajoutez une colonne à une table, elle doit être dans son propre lot. Si vous essayez de SELECT la nouvelle colonne dans le même lot, cela échoue car au moment de l'analyse / compilation, la colonne n'existe pas.

GO est utilisé par les outils SQL pour résoudre ce problème à partir d'un seul script: ce n'est pas un mot clé SQL et n'est pas reconnu par le moteur.

Ce sont 2 exemples concrets d'utilisation quotidienne des lots.

Edit: Dans votre exemple, vous n'avez pas besoin de GO ...

Edit 2, exemple. Vous ne pouvez pas supprimer, créer et autoriser dans un seul lot ... surtout, où est la fin de la procédure stockée?

IF OBJECT_ID ('dbo.uspDoStuff') IS NOT NULL
    DROP PROCEDURE dbo.uspDoStuff
GO
CREATE PROCEDURE dbo.uspDoStuff
AS
SELECT Something From ATable
GO
GRANT EXECUTE ON dbo.uspDoStuff TO RoleSomeOne
GO
gbn
la source
4

Parfois, il est nécessaire d'exécuter la même commande ou le même ensemble de commandes encore et encore. Cela peut être pour insérer ou mettre à jour des données de test ou cela peut être pour charger votre serveur pour des tests de performances. Quel que soit le besoin, le moyen le plus simple de le faire est de configurer une boucle while et d'exécuter votre code, mais dans SQL 2005, il existe un moyen encore plus simple de le faire.

Supposons que vous souhaitiez créer une table de test et la charger avec 1000 enregistrements. Vous pouvez émettre la commande suivante et elle exécutera la même commande 1000 fois:

CREATE TABLE dbo.TEST (ID INT IDENTITY (1,1), ROWID uniqueidentifier)
GO
INSERT INTO dbo.TEST (ROWID) VALUES (NEWID()) 
GO 1000

source: http://www.mssqltips.com/tip.asp?tip=1216

Autre que cela, il marque la "fin" d'un bloc SQL (par exemple dans une procédure stockée) ... Ce qui signifie que vous êtes à nouveau dans un état "propre" ... eG: Paramètres utilisés dans l'instruction avant la réinitialisation du code ( n'est plus défini)

Steav
la source
Ok, alors pourquoi avez-vous besoin de GO. Pour que vous sachiez que la table a été créée avant l'exécution de l'instruction d'insertion? Je ne comprends toujours pas.
PositiveGuy
Voir La façon dont je pense à ce sujet, c'est que si je n'ai pas de GO dans votre exemple, la table est créée en premier, elle est là maintenant, donc l'insert devrait fonctionner. Je ne comprends pas à quoi sert le GO si j'ai créé le tableau ... il est disponible pour le prochain insert n'est-ce pas?!?!?!
PositiveGuy
2
@coffeeaddict: non. le "lot" est analysé et compilé en une seule fois. Au moment de la compilation, dbo.TEST n'existe pas. Vous n'instanciez pas un objet et SQL n'est pas du code procédural ligne par ligne
gbn
3

Comme tout le monde l'a déjà dit, "GO" ne fait pas partie de T-SQL. «GO» est un séparateur de lots dans SSMS , une application client utilisée pour soumettre des requêtes à la base de données. Cela signifie que les variables déclarées et les variables de table ne persisteront pas du code avant le "GO" au code suivant.

En fait, GO est simplement le mot par défaut utilisé par SSMS. Cela peut être modifié dans les options si vous le souhaitez. Pour vous amuser un peu, changez l'option sur le système de quelqu'un d'autre pour utiliser "SELECT" comme séparateur de lots au lieu de "GO". Pardonne mon rire cruel.

Le Dixie Flatline
la source
1
Il y a en fait un point sérieux à souligner ici: vous devez traiter GO comme s'il s'agissait d'un mot-clé même si ce n'est pas le cas. Vous ne devriez jamais non plus le changer. Les bogues causés par la réutilisation d'identificateurs spéciaux peuvent être très difficiles à déboguer.
Jørgen Fogh
@The Dixie Flatline: êtes-vous sûr que les variables déclarées ne persistent pas? Dans MSSQL 2016, j'obtiens une erreur "variable déjà déclarée" lors de l'exécution: declare $ test int; set $ test = 5; sélectionnez $ test go; déclarer $ test int; - Remplacez $ par <at>, impossible d'utiliser plusieurs <at> dans les commentaires SE.
Wouter
0

Il est utilisé pour diviser les blocs logiques. Votre code est interprété en ligne de commande sql et cela indique le prochain bloc de code.

Mais il pourrait être utilisé comme instruction récursive avec un numéro spécifique.

Essayer:

exec sp_who2  
go 2

Certaines déclarations doivent être délimitées par GO:

use DB
create view thisViewCreationWillFail
Deadsheep39
la source