Gemäß der UPDATE
documentation erwirbt eine UPDATE
immer eine exklusive Sperre für die gesamte Tabelle. Ich frage mich jedoch, ob die exklusive Sperre erworben wird, bevor die zu aktualisierenden Zeilen bestimmt werden oder nur kurz vor dem eigentlichen Update.Ist eine Transaktion, die nur eine einzige isolierte Tabelle aktualisiert?
Mein konkretes Problem ist, dass ich eine verschachtelte SELECT
in meinem UPDATE
aussehen:
UPDATE Tasks
SET Status = 'Active'
WHERE Id = (SELECT TOP 1 Id
FROM Tasks
WHERE Type = 1
AND (SELECT COUNT(*)
FROM Tasks
WHERE Status = 'Active') = 0
ORDER BY Id)
Jetzt frage ich mich, ob es wirklich ist garantiert, dass es genau eine Aufgabe ist mit Status = 'Active'
danach, ob in parallel die gleiche Aussage kann mit einer anderen Art ausgeführt werden:
UPDATE Tasks
SET Status = 'Active'
WHERE Id = (SELECT TOP 1 Id
FROM Tasks
WHERE Type = 2 -- <== The only difference
AND (SELECT COUNT(*)
FROM Tasks
WHERE Status = 'Active') = 0
ORDER BY Id)
Wenn für beide Aussagen die Reihen bestimmt würde sich ändern, bevor die Sperre erworben wird, könnte ich am Ende mit zwei aktiven Aufgaben, die ich verhindern muss.
Wenn dies der Fall ist, wie kann ich das verhindern? Kann ich das verhindern, ohne die Transaktionsstufe auf SERIALIZABLE
zu setzen oder mit Sperrhinweisen zu verfahren?
Von der Antwort auf Is a single SQL Server statement atomic and consistent? habe ich gelernt, dass das Problem auftritt, wenn der verschachtelte SELECT
auf eine andere Tabelle zugreift. Ich bin mir jedoch nicht sicher, ob ich mich um dieses Problem kümmern muss, wenn nur die aktualisierte Tabelle betroffen ist.
dieser Dokumentation ist sowieso falsch. Updates sperren im Allgemeinen nicht die gesamte Tabelle. –
Hm, ok, danke. Wo finde ich dann die richtige Dokumentation? – lex82
Die Dokumentation sagt nicht, dass ein 'UPDATE' die gesamte Tabelle sperrt. Es besagt, dass es eine exklusive Sperre erwirbt, aber eine exklusive Sperre muss nicht auf der gesamten Tabelle sein. –