sql >> Databasteknik >  >> RDS >> Sqlserver

Är en enda SQL Server-sats atomär och konsekvent?

Jag har arbetat under antagandet att en enda sats i SQL Server är konsekvent

Det antagandet är fel. Följande två transaktioner har identisk låssemantik:

STATEMENT

BEGIN TRAN; STATEMENT; COMMIT

Ingen skillnad alls. Enstaka uttalanden och auto-commits ändrar ingenting.

Så att slå samman all logik till ett påstående hjälper inte (om det gör det var det av misstag eftersom planen ändrades).

Låt oss lösa problemet. SERIALIZABLE kommer att åtgärda inkonsekvensen du ser eftersom det garanterar att dina transaktioner beter sig som om de utfördes entrådigt. På motsvarande sätt beter de sig som om de avrättades omedelbart.

Du kommer att få dödlägen. Om du är ok med en återförsök-loop är du klar vid det här laget.

Om du vill investera mer tid, använd låstips för att tvinga fram exklusiv åtkomst till relevant data:

UPDATE Gifts  -- U-locked anyway
SET GivenAway = 1
WHERE GiftID = (
   SELECT TOP 1 GiftID
   FROM Gifts WITH (UPDLOCK, HOLDLOCK) --this normally just S-locks.
   WHERE g2.GivenAway = 0
    AND (SELECT COUNT(*) FROM Gifts g2 WITH (UPDLOCK, HOLDLOCK) WHERE g2.GivenAway = 1) < 5
   ORDER BY g2.GiftValue DESC
)

Du kommer nu att se minskad samtidighet. Det kan vara helt okej beroende på din belastning.

Själva naturen av ditt problem gör det svårt att uppnå samtidighet. Om du behöver en lösning för det måste vi tillämpa mer invasiva tekniker.

Du kan förenkla UPPDATERINGEN lite:

WITH g AS (
   SELECT TOP 1 Gifts.*
   FROM Gifts
   WHERE g2.GivenAway = 0
    AND (SELECT COUNT(*) FROM Gifts g2 WITH (UPDLOCK, HOLDLOCK) WHERE g2.GivenAway = 1) < 5
   ORDER BY g2.GiftValue DESC
)
UPDATE g  -- U-locked anyway
SET GivenAway = 1

Detta tar bort en onödig anslutning.



  1. Hur kan jag sortera en kolumn "Versionsnummer" allmänt med hjälp av en SQL Server-fråga

  2. Flera CTE i en enda fråga

  3. Hur testar jag i WiX om det finns en registernyckel (inte värde) för Oracle ODP.Net

  4. Oracle SQL Where-klausul för att hitta datumposter äldre än 30 dagar