Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Czy pojedyncza instrukcja SQL Server jest niepodzielna i spójna?

Działam z założeniem, że pojedyncza instrukcja w SQL Server jest spójna

To założenie jest błędne. Następujące dwie transakcje mają identyczną semantykę blokowania:

STATEMENT

BEGIN TRAN; STATEMENT; COMMIT

Żadna różnica. Pojedyncze oświadczenia i automatyczne zatwierdzenia niczego nie zmieniają.

Więc scalanie całej logiki w jedno stwierdzenie nie pomaga (jeśli tak, to przez przypadek, ponieważ plan się zmienił).

Rozwiążmy problem pod ręką. SERIALIZABLE naprawi niespójność, którą widzisz, ponieważ gwarantuje, że Twoje transakcje zachowują się tak, jakby były wykonywane jednowątkowo. Podobnie zachowują się tak, jakby zostały wykonane natychmiast.

Będziesz mieć impas. Jeśli możesz wykonać pętlę ponawiania, w tym momencie wszystko jest gotowe.

Jeśli chcesz zainwestować więcej czasu, zastosuj wskazówki dotyczące blokowania, aby wymusić wyłączny dostęp do odpowiednich danych:

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
)

Zobaczysz teraz zmniejszoną współbieżność. To może być całkowicie w porządku w zależności od obciążenia.

Sam charakter Twojego problemu sprawia, że ​​osiągnięcie współbieżności jest trudne. Jeśli potrzebujesz rozwiązania, musimy zastosować bardziej inwazyjne techniki.

Możesz nieco uprościć UPDATE:

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

Pozwala to pozbyć się jednego niepotrzebnego przyłączenia.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak mogę pogrupować według kolumny daty i godziny bez uwzględniania czasu?

  2. Jak działa funkcja QUOTENAME() w programie SQL Server (T-SQL)

  3. Usuwanie zduplikowanych wierszy (na podstawie wartości z wielu kolumn) z tabeli SQL

  4. SYSDATETIME() vs GETDATE() w SQL Server:jaka jest różnica?

  5. Efektywnie konwertuj wiersze na kolumny w serwerze sql