Czy odłączenie sieci zatrzymuje zapytanie?

13

Niedawno wykonałem zapytanie o aktualizację względem 100 000 rekordów. Zdałem sobie sprawę, że popełniłem błąd podczas działania zapytania i szybko odłączyłem kabel sieciowy.

Czy zapytanie o aktualizację?

  1. zatrzymać przetwarzanie i całkowicie wycofać?
  2. kontynuować przetwarzanie do zakończenia i zatwierdzić?
  3. zatrzymać przetwarzanie i zostawić zaktualizowaną tylko część wierszy docelowych?
robocop
źródło
2
gdy zapytanie trafi na serwer, będzie kontynuowane, chyba że anulujesz zapytanie na serwerze.
JP Chauhan
1
Komentarz Martina zapewnia bezpośrednią odpowiedź na twoje pytanie, robocop. Jeśli sieć powiadomi SQL Server o rozłączeniu przed zakończeniem zapytania, SQL Server je przywróci. W przeciwnym razie, jeśli kwerenda zostanie zakończona przed powiadomieniem SQL Server o rozłączeniu sieci, zostanie ona zatwierdzona. W żadnym wypadku (przy założeniu, że napisałeś zapytanie dotyczące pojedynczej aktualizacji) SQL Server nie wykona częściowej aktualizacji.
Nick Chammas

Odpowiedzi:

22

Jak wspomniano Nick i Martin, ostateczny stan twojego zapytania zależy od tego, czy SQL Server wie o wyciągnięciu kabla sieciowego przed zakończeniem zapytania. Z Books Online (choć uważam za interesujące, że istnieją równoważne tematy w 2000 , 2005 , 2008 i 2008 R2 , ale nie 2012 lub 2014):

Jeśli błąd uniemożliwia pomyślne zakończenie transakcji, SQL Server automatycznie wycofuje transakcję i zwalnia wszystkie zasoby posiadane przez transakcję. Jeśli połączenie sieciowe klienta z wystąpieniem aparatu bazy danych zostanie zerwane, wszelkie zaległe transakcje dla połączenia zostaną wycofane, gdy sieć powiadomi o wystąpieniu przerwy. Jeśli aplikacja kliencka ulegnie awarii lub komputer kliencki ulegnie awarii lub zostanie zrestartowany, spowoduje to również przerwanie połączenia, a wystąpienie aparatu bazy danych cofa wszelkie zaległe połączenia, gdy sieć powiadomi go o przerwaniu. Jeśli klient wyloguje się z aplikacji, wszelkie zaległe transakcje zostaną wycofane.

(Nawiasem mówiąc, to słowo połączenia w drugim ostatnim zdaniu prawdopodobnie miało być transakcją . Nie wiem, jak się wycofuje połączenie).

W podobny sposób SQL Server może cofać lub ponawiać transakcje podczas odzyskiwania po nieoczekiwanym zamknięciu serwera, co będzie zależeć od stanu transakcji w momencie zamknięcia. Widziałem, jak ludzie używają tej taktyki, aby osiągnąć to, co próbowaliście zrobić (anulować transakcję), a kiedy serwer uruchomił się ponownie, znaczna część pracy została po prostu przerobiona (więc efekt netto ich gwałtownej reakcji był znacznie bliższy do zera niż się spodziewali).

Zamiast więc poddawać się temu, zamiast robić drastyczne rzeczy w panice, jak szarpanie kabla sieciowego lub wyłączanie maszyny, sugeruję w przyszłości lepszą dyscyplinę w uruchamianiu zapytań ad hoc względem ważnych systemów. Na przykład zamiast:

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

Masz to:

BEGIN TRANSACTION;

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

-- COMMIT TRANSACTION;
-- ROLLBACK TRANSACTION;

Następnie, jeśli aktualizacja rzeczywiście była poprawna, możesz podświetlić tę COMMITczęść i uruchomić ją. Jeśli nie, możesz spokojnie zaznaczyć tę ROLLBACKczęść i uruchomić ją. Możesz nawet użyć dodatków, takich jak SSMS Tools Pack, aby edytować New Queryszablon, aby uwzględnić ten szablon.

Teraz nadal może sprawiać kłopoty w przypadku uruchomienia zapytania, a następnie nie zatwierdzenia ani wycofania, ponieważ teraz transakcja blokuje innych użytkowników. Jest to jednak lepsze niż nieodwracalne modyfikowanie danych.

I oczywiście, jak zawsze, masz kopię zapasową, na której możesz polegać.

Aaron Bertrand
źródło
5
To doskonała rada i rozwiązuje problem źródłowy OP, ale w rzeczywistości nie odpowiada na pytanie, czy zapytanie nadal działa, czy nie.
Nick Chammas
3
Dzięki @Nick, moją motywacją było zajęcie się przyczyną (która wywołała pytanie), a nie objawem, ale zaktualizowałem swoją odpowiedź.
Aaron Bertrand
8

@Aaron ma rację. Najlepszym rozwiązaniem jest utworzenie transakcji przed poleceniami. Jeśli nie pamiętasz, aby to zrobić, jedną z opcji jest przejście do Tools-Optionsustawień i włączenie SET IMPLICIT_TRANSACTIONS. Spowoduje to automatyczne rozpoczęcie transakcji, gdy tylko niektóre polecenia zostaną uruchomione. Obejmuje to UPDATE, DELETEitd. To wydaje się być dość pełna lista dowolnego polecenia, które "change"coś. SELECTjest również uwzględniony na liście i willrozpoczyna transakcję. Można zobaczyć pełną listę poleceń, które zaczynają transakcji będzie to ustawienie tutaj . Nie utworzy transakcji, jeśli została już uruchomiona. Wadą tego jest to, że będziesz musiał pamiętać COMMITpo każdej dokonanej zmianie.

UWAGA: W oparciu o sugestię @ Aarona zamierzam to podkreślić.

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

Zasadniczo BEGINrezygnujesz z zapominania o transakcji i zepsucia czegoś, za zapominanie COMMITo transakcji i zawieszenie jej, jeśli zostawisz ją otwartą, a następnie wyjdziesz na cały dzień. Testowałem właśnie zamykając okno zapytania, sądząc, że wycofuje ono moją transakcję, ale poprosiło mnie, jeśli chcę zatwierdzić lub wycofać transakcję.

wprowadź opis zdjęcia tutaj

Kenneth Fisher
źródło
Właściwie: SELECT będzie uruchomić transakcji (która jest również udokumentowane w linku pisał)
a_horse_with_no_name
Dzięki {a_horse_with_no_name za złapanie tego! Nie czytałem wystarczająco uważnie i zaczynałem od starej pamięci (to oczywiście było złe).
Kenneth Fisher
1
Jest to post pomocny, ale tak naprawdę nie odpowiada na pytanie PO o to, czy zapytanie nadal działa, czy nie.
Nick Chammas
2
Miało to być dodatkiem do odpowiedzi @ Aarona. W komentarzu było po prostu za dużo.
Kenneth Fisher
2

myślę, że to naprawdę zależy:

jeśli polecenie dotrze już do serwera przed odłączeniem kabla sieciowego, polecenie nadal będzie działać normalnie.

jeśli masz TransactionScope (używany w .Net, nie jestem pewien, że w innych językach) do enkapsulacji wszystkich poleceń aktualizacji, prawdopodobnie możesz zatrzymać transakcję, która zostanie zatwierdzona, tylko jeśli transakcja nie została wykonana, ale nie ma gwarancji. .

Rex
źródło
2
Powiedziałeś „jeśli polecenie dotrze już do serwera przed odłączeniem kabla sieciowego, polecenie nadal będzie działać normalnie”. Jest to sprzeczne ze stroną BOL programu SQL Server, do której Martin odsyłał powyżej. Zobacz „Błędy podczas przetwarzania transakcji” .
Nick Chammas
masz rację. z określoną transakcją polecenie zostanie automatycznie wycofane. ale jak się przekonaliśmy, kiedy nie podano jawnie żadnej transakcji, polecenie (aktualizacja wsadowa bez transakcji) zostało wykonane w pełni, nawet zatrzymaliśmy naszą aplikację w środku, co faktycznie zrywało połączenie - ale nie jest to naprawdę dobry przykład na czas prawdopodobnie nie było poprawne. prawdopodobnie dobrze jest zrobić kilka testów
Rex