La disconnessione della rete interrompe una query?


13

Di recente ho eseguito una query di aggiornamento su 100.000 record. Mi sono reso conto di aver commesso un errore durante l'esecuzione della query e di aver scollegato rapidamente il cavo di rete.

Fa la query di aggiornamento

  1. interrompere l'elaborazione e ripristinare completamente?
  2. continuare l'elaborazione fino al completamento e impegnarsi?
  3. interrompere l'elaborazione e lasciare aggiornata solo una parte delle righe di destinazione?

2
una volta che una query ha colpito il server continuerà a meno che tu non abbia annullato la query sul server.
JP Chauhan,


1
Il commento di Martin fornisce la risposta diretta alla tua domanda, robocop. Se la rete notifica a SQL Server la disconnessione prima che la query venga completata, SQL Server eseguirà il rollback. Altrimenti, se la query viene completata prima che venga comunicato a SQL Server che c'era una disconnessione dalla rete, verrà eseguito il commit. In nessun caso (supponendo che tu abbia scritto una singola query di aggiornamento) SQL Server eseguirà un aggiornamento parziale.
Nick Chammas,

Risposte:


22

Come accennato da Nick e Martin, l'eventuale stato della query dipende dal fatto che SQL Server sia a conoscenza del passaggio del cavo di rete prima del completamento della query. Da Books Online (anche se trovo interessante che ci siano argomenti equivalenti per questo nel 2000 , 2005 , 2008 e 2008 R2 , ma non nel 2012 o 2014):

Se un errore impedisce il corretto completamento di una transazione, SQL Server ripristina automaticamente la transazione e libera tutte le risorse trattenute dalla transazione. Se la connessione di rete del client a un'istanza del Motore di database viene interrotta, tutte le transazioni in sospeso per la connessione vengono ripristinate quando la rete notifica l'istanza dell'interruzione. Se l'applicazione client ha esito negativo o se il computer client si arresta o viene riavviato, anche questa interrompe la connessione e l'istanza del Motore di database ripristina eventuali connessioni in sospeso quando la rete lo avvisa dell'interruzione. Se il client si disconnette dall'applicazione, tutte le transazioni in sospeso vengono ripristinate.

(A parte questo, i collegamenti a parola nell'ultima frase erano probabilmente intesi come transazioni . Non so come si fa a ripristinare una connessione.)

In modo simile, SQL Server potrebbe annullare o ripetere le transazioni durante il ripristino dopo l'arresto imprevisto del server, e ciò dipenderà dallo stato della transazione al momento dell'arresto. Ho visto persone usare questa tattica per ottenere ciò che stavi cercando di fare (annullare la transazione) e quando il server è stato riavviato gran parte del lavoro è stato semplicemente rifatto (quindi l'effetto netto della loro reazione istintiva era molto più vicino a zero di quanto previsto).

Quindi piuttosto che essere soggetto a questo, invece di fare cose drastiche in preda al panico, come strappare un cavo di rete o spegnere la macchina, suggerisco in futuro di avere una migliore disciplina sull'esecuzione di query ad hoc contro sistemi importanti. Ad esempio, anziché:

UPDATE dbo.sometable 
-- where *oops* I forgot this part

Avere questo:

BEGIN TRANSACTION;

UPDATE dbo.sometable
-- where *oops* I forgot this part

-- COMMIT TRANSACTION;
-- ROLLBACK TRANSACTION;

Quindi, se l'aggiornamento è stato effettivamente corretto, è possibile evidenziare la COMMITparte ed eseguirlo. In caso contrario, puoi evidenziare con calma la ROLLBACKparte ed eseguirla. Puoi anche utilizzare componenti aggiuntivi come SSMS Tools Pack per modificare il tuo New Querymodello per includere quella piastra di caldaia.

Ora potresti comunque metterti nei guai nel caso in cui eseguissi la query e non eseguissi il commit o il rollback, perché ora la tua transazione sta bloccando altri utenti. Ma è meglio quindi modificare irrevocabilmente i dati.

E ovviamente, come sempre, hai un backup su cui puoi contare.


5
Questo è un consiglio eccellente e affronta la radice del problema del PO, ma in realtà non risponde alla domanda se la query ha continuato a funzionare o meno.
Nick Chammas,

3
Grazie @Nick, la mia motivazione è stata quella di affrontare la causa (che ha stimolato la domanda), non il sintomo, ma ho aggiornato la mia risposta.
Aaron Bertrand

8

@Aaron è corretto. Creare una transazione prima dei tuoi comandi è la soluzione migliore. Se non ricordi di farlo, un'opzione è accedere Tools-Optionsall'impostazione e attivare SET IMPLICIT_TRANSACTIONS. Ciò avvierà automaticamente una transazione non appena vengono eseguiti determinati comandi. Ciò include UPDATE, DELETEecc. Questo sembra essere un elenco abbastanza completo di qualsiasi comando che farebbe "change"qualcosa. SELECTè anche incluso nell'elenco e willavvia una transazione. Puoi visualizzare un elenco completo dei comandi che avviano una transazione con questa impostazione qui . Non creerà una transazione se ne è già stata avviata una. Ora il lato negativo di questo è che dovrai ricordarti di COMMITdopo ogni modifica apportata.

NOTA: Sulla base del suggerimento di @ Aaron, lo sottolineo nuovamente.

This is very important!  You will have to remember to COMMIT after any change made!

Fondamentalmente stai scambiando dimenticando BEGINuna transazione e rovinando qualcosa, per dimenticare COMMITuna transazione e averla sospesa se la lasci aperta e poi parti per la giornata. Ho testato semplicemente chiudendo una finestra di query pensando che avrebbe eseguito il rollback della mia transazione, tuttavia mi ha suggerito se volevo eseguire il commit o il rollback della transazione.

inserisci qui la descrizione dell'immagine


In realtà: SELECT sarà avviare una transazione (che è anche documentato nel link che hai postato)
a_horse_with_no_name

Grazie @a_horse_with_no_name per averlo scoperto! Non ho letto abbastanza attentamente e stavo uscendo da un vecchio ricordo (era ovviamente sbagliato).
Kenneth Fisher,

1
Questo è un post utile, ma in realtà non risponde alla domanda del PO se la query ha continuato a funzionare o meno.
Nick Chammas,

2
Era inteso come aggiunta alla risposta di @ Aaron. È stato troppo per inserire un commento.
Kenneth Fisher,

2

penso che dipenda davvero:

se il comando raggiunge già il server prima di aver scollegato il cavo di rete, il comando continuerà comunque a funzionare normalmente.

se si dispone di un TransactionScope (utilizzato in .Net, non sicuro in altre lingue) per incapsulare tutti i comandi di aggiornamento, probabilmente è possibile interrompere il commit della transazione solo se non è stata eseguita la transazioneScope.Complete (), ma nessuna garanzia. .


2
Hai detto "se il comando raggiunge già il server prima di aver scollegato il cavo di rete, il comando continuerà comunque ad essere eseguito normalmente". Ciò è contraddetto dalla pagina BOL di SQL Server a cui Martin ha collegato sopra. Vedere "Errori durante l'elaborazione delle transazioni" .
Nick Chammas,

hai ragione. con una transazione specificata, il comando eseguirà il rollback automaticamente. ma come abbiamo sperimentato, quando nessuna transazione è stata specificata in modo esplicito, il comando (un aggiornamento batch senza una transazione) è stato eseguito completamente anche se abbiamo interrotto la nostra applicazione nel mezzo, il che ha effettivamente interrotto la connessione - ma non è davvero un buon esempio come i tempi probabilmente non era corretto. probabilmente è bene fare dei test per questo
Rex il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.