Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Une seule instruction SQL Server est-elle atomique et cohérente ?

J'ai fonctionné en supposant qu'une seule instruction dans SQL Server est cohérente

Cette hypothèse est fausse. Les deux transactions suivantes ont une sémantique de verrouillage identique :

STATEMENT

BEGIN TRAN; STATEMENT; COMMIT

Aucune différence. Les instructions simples et les validations automatiques ne changent rien.

Donc, fusionner toute la logique en une seule instruction n'aide pas (si c'est le cas, c'est par accident parce que le plan a changé).

Réglons le problème à portée de main. SERIALIZABLE corrigera l'incohérence que vous voyez car cela garantit que vos transactions se comportent comme si elles s'exécutaient en un seul thread. De manière équivalente, ils se comportent comme s'ils s'exécutaient instantanément.

Vous obtiendrez des impasses. Si vous êtes d'accord avec une boucle de nouvelle tentative, vous avez terminé à ce stade.

Si vous souhaitez investir plus de temps, appliquez des conseils de verrouillage pour forcer l'accès exclusif aux données pertinentes :

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
)

Vous verrez maintenant une simultanéité réduite. Cela peut être tout à fait correct selon votre charge.

La nature même de votre problème rend difficile la réalisation de la concurrence. Si vous avez besoin d'une solution pour cela, nous aurions besoin d'appliquer des techniques plus invasives.

Vous pouvez simplifier un peu la MISE À JOUR :

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

Cela supprime une jointure inutile.