Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Ist in tsql eine Einfügung mit einer Select-Anweisung in Bezug auf die Parallelität sicher?

Wie Paul schreibt:Nein, es ist nicht sicher , für die ich empirische Beweise hinzufügen möchte:Erstellen Sie eine Tabelle Table_1 mit einem Feld ID und einen Datensatz mit dem Wert 0 . Führen Sie dann den folgenden Code gleichzeitig in zwei Management Studio-Abfragefenstern aus :

declare @counter int
set @counter = 0
while @counter < 1000
begin
  set @counter = @counter + 1

  INSERT INTO Table_1
    SELECT MAX(ID) + 1 FROM Table_1 

end

Dann ausführen

SELECT ID, COUNT(*) FROM Table_1 GROUP BY ID HAVING COUNT(*) > 1

Auf meinem SQL Server 2008 ist eine ID (662 ) wurde zweimal erstellt. Daher ist die auf einzelne Anweisungen angewendete Standardisolationsstufe nicht ausreichend.

BEARBEITEN:Klar, Umbruch des INSERT mit BEGIN TRANSACTION und COMMIT wird es nicht beheben, da die Standardisolationsstufe für Transaktionen immer noch READ COMMITTED ist , was nicht ausreicht. Beachten Sie, dass Sie die Transaktionsisolationsstufe auf REPEATABLE READ setzen ist auch nicht ausreichend. Die einzige Möglichkeit, den obigen Code sicher zu machen ist hinzuzufügen

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

oben. Dies führte jedoch bei meinen Tests hin und wieder zu Deadlocks.

BEARBEITEN:Die einzige Lösung, die ich gefunden habe, ist und sicher keine Deadlocks erzeugt (zumindest in meinen Tests), ist es, die Tabelle explizit exklusiv zu sperren (hier reicht die Standard-Transaktionsisolationsstufe aus). Aber Vorsicht; diese Lösung könnte töten Leistung:

...loop stuff...
    BEGIN TRANSACTION

    SELECT * FROM Table_1 WITH (TABLOCKX, HOLDLOCK) WHERE 1=0

    INSERT INTO Table_1
      SELECT MAX(ID) + 1 FROM Table_1 

    COMMIT
...loop end...