Introduktion
For nylig kom en af mine kollegaer til mig i desperation og ejede over, at han havde udstedt en opdateringserklæring uden en WHERE-klausul på en nøgleapplikationstabel. Implikationerne på forsiden ville være alvorlige, så han kom direkte til mig, fordi han havde akut brug for hjælp til at vende situationen på nogen måde, før e-mails og eskalering begyndte at strømme ind.
Da vi undersøgte situationen, fandt vi ud af, at ændringerne ikke er blevet anvendt i den sekundære database. I de fleste tilfælde er forsinkelsen mellem vores primære og sekundære databaser tyve minutter (vi har lidt svimlende for at undgå ydeevneproblemer). Fordi min kollega bad om hjælp umiddelbart efter at have opdaget fejlen, var vi i stand til at gendanne dataene fra den sekundære database. Jeg beskrev værdien af en sådan forsinkelse i denne artikel .
Scenariogennemgang
Scenariet, jeg beskrev ovenfor, er ikke ualmindeligt. En af grundene til, at dette sker for almindelige SQL Server-brugere, er, at SQL Server bruger det, der kaldes implicitte transaktioner. Implicitte transaktioner er slået FRA som standard, hvilket betyder, at SQL Server ikke forventer, at du udsteder en COMMIT TRANSACTION-sætning i slutningen af hver erklæring. I realiteten begås hver erklæring automatisk. Dette er praktisk og hjælper med at undgå situationer, hvor sessioner, der endnu ikke er forpligtet, ender med at låse ressourcer og påvirke ydeevnen. Brent Ozar giver flere detaljer om præstationsimplikationerne af IMPLICIT TRANSACTIONS =ON.
Men en lille ulempe ved denne konfiguration (IMPLICITTE TRANSAKTIONER =FRA) er, at brugerne ikke har mulighed for at genoverveje en erklæring og udstede en ROLLBACK, som er meget almindelig i Oracle. Fig. 1 viser de tilgængelige ANSI-forespørgselsmuligheder i SQL Server Management Studio.
Fig. 1 ANSI-standarder i SQL Server Management Studio
Brug af implicitte transaktioner
I bund og grund er problemet, vi står over for i denne standardkonfiguration eller vores mest ønskværdige klientværktøj, at vi ikke kan TILBAGE, når vi først har udført en SQL-sætning. Vi kan omgå dette ved at aktivere IMPLICITTE TRANSAKTIONER i vores session. Dette vil give os mulighed for at TILBAGE transaktioner, hvis vi har brug for det. Fig. 2 og Fig. 4 viser os, at vi kun kan have denne indstilling aktiveret for én session, selvom dette ikke fjerner risikoen for, at brugersessionen blokerer andre, hvis der ikke udstedes en ROLLBACK eller COMMIT.
Fig. 2 IMPLICITTE TRANSAKTIONER TIL i én session
-- Listing 1: UPDATE Table TAB2 with IMPLICIT_TRANSACTIONS ON SET IMPLICIT_TRANSACTIONS ON DECLARE @IMPLICIT_TRANSACTIONS VARCHAR(3) = 'OFF'; IF ( (2 & @@OPTIONS) = 2 ) SET @IMPLICIT_TRANSACTIONS = 'ON'; SELECT @IMPLICIT_TRANSACTIONS AS IMPLICIT_TRANSACTIONS; USE KTrain GO SELECT * FROM Tab2; GO UPDATE TAB2 SET countryCode='SA' -- WHERE fname='Joyce'; GO SELECT * FROM Tab2; GO
Fig. 3 Alle rækker opdateret
For at illustrere den løsning, der er beskrevet her, lad os se på SQL-koden i liste 1. Lad os antage, at en almindelig SQL Server-bruger, en juniorudvikler, har fået et sæt scripts til at udføre under visse betingelser . I scriptet er WHERE-sætningen blevet kommenteret ud, fordi det forventes, at hver gang de udfører dette script, skal de ændre prædikatet. Dette er selvfølgelig en simpel use case, og risikoen kan adresseres på flere måder, men vi vil blot vise muligheden for at udføre en ROLLBACK.
Husk, at vi allerede har slået IMPLICIT TRANSACTION til, så når vi udfører denne sætning, forventer SQL Server, at vi enten COMMIT eller ROLLBACK transaktionen. Udviklerens hensigt er at opdatere Joyce Afams landekode til ’SA’, siden hun er immigreret til Sydafrika. Fig. 3 viser os, at udvikleren, mens han forsøgte at gøre dette, ved et uheld har opdateret alle rækker med værdien SA som countryCode . De bemærker dette og udsteder en ROLLBACK.
Fig. 4 Udsende ROLLBACK
Fig. 5 IMPLICITTE TRANSAKTIONER TIL i en anden session
I den anden session, hvor vi ikke har slået IMPLICITTE TRANSAKTIONER til, opdager vi dog, at udvikleren ikke er i stand til at genoprette sin fejl. De kan ikke udstede en ROLLBACK i dette tilfælde. Gendannelse ville derefter medføre datagendannelse.
Fig. 6 TILBAGE ikke muligt uden IMPLICITTE TRANSAKTIONER PÅ
Brug af eksplicitte transaktioner
En anden tilgang til at opnå den samme effekt er at indeslutte DML i en transaktion ved eksplicit at angive BEGIN TRAN. Igen er det meget vigtigt at gennemføre transaktionen – ved at bruge enten COMMIT eller ROLLBACK. I forbindelse med denne diskussion udsteder vi en ROLLBACK, da vi er klar over, at der er en fejl i koden.
-- Listing 2: UPDATE Table TAB2 with Explicit Transaction BEGIN TRAN GO USE KTrain GO SELECT * FROM Tab2; GO UPDATE TAB2 SET countryCode='GH' -- WHERE fname='Joyce'; GO SELECT * FROM Tab2; GO ROLLBACK; SELECT * FROM Tab2; GO - Listing 3: Corrected UPDATE Statement BEGIN TRAN GO USE KTrain GO SELECT * FROM Tab2; GO UPDATE TAB2 SET countryCode='SA' WHERE fname='Joyce'; GO SELECT * FROM Tab2; GO
Konklusion
I denne artikel har vi kort berørt en god løsning til at skabe muligheder for ROLLBACK og dermed afbøde brugerfejl som følge af forkert DML. Vi har også fremhævet en vigtig risiko ved denne tilgang, som er utilsigtet blokering. En DBA kan påbegynde undersøgelser af den mulige tilstedeværelse af denne risiko ved at forespørge sys.dm_tran_session_transactions, sys.dm_tran_locks , og lignende dynamiske styringsobjekter.
Referencer
Løsning af datatab ved hjælp af logforsendelse med forsinket gendannelse
Indstil implicitte transaktioner
Sæt implicitte transaktioner til en dårlig idé
DMV'er til transaktioner