sql >> Databasteknik >  >> RDS >> Sqlserver

I tsql är en Insert med en Select-sats säker när det gäller samtidighet?

Som Paul skriver:Nej, det är inte säkert , som jag skulle vilja lägga till empiriska bevis för:Skapa en tabell Table_1 med ett fält ID och en post med värdet 0 . Kör sedan följande kod samtidigt i två Management Studio-frågefönster :

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

Kör sedan

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

På min SQL Server 2008, ett ID (662 ) skapades två gånger. Således är standardisoleringsnivån som tillämpas på enstaka satser inte tillräckligt.

EDIT:Tydligen, linda in INSERT med BEGIN TRANSACTION och COMMIT kommer inte att fixa det, eftersom standardisoleringsnivån för transaktioner fortfarande är READ COMMITTED , vilket inte är tillräckligt. Observera att inställning av transaktionsisoleringsnivån till REPEATABLE READ är också inte tillräckligt. Det enda sättet att göra ovanstående kod säker är att lägga till

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

på toppen. Detta orsakade dock dödlägen då och då i mina tester.

EDIT:Den enda lösningen jag hittade som är säker och inte producerar dödlägen (åtminstone i mina tester) är att explicit låsa tabellen exklusivt (standard transaktionsisoleringsnivå är tillräcklig här). Akta dig dock; den här lösningen kan döda prestanda:

...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...


  1. ORA-24408:kunde inte generera unikt servergruppsnamn

  2. hur ersätter den accentuerade bokstaven i en varchar2-kolumn i Oracle

  3. Använda SolarWinds Serv-U på Linux med en SQL Server Authentication Database

  4. Komplett process för att kopiera tabell från en databas till en annan (export-import) i SQL Server