sql >> Database teknologi >  >> RDS >> Sqlserver

I tsql er en Insert med en Select-sætning sikker med hensyn til samtidighed?

Som Paulus skriver:Nej, det er ikke sikkert , som jeg gerne vil tilføje empirisk bevis for:Opret en tabel Table_1 med ét felt ID og én post med værdien 0 . Udfør derefter følgende kode samtidigt i to Management Studio-forespørgselsvinduer :

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

Udfør derefter

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

På min SQL Server 2008, ét ID (662 ) blev oprettet to gange. Således er standardisolationsniveauet anvendt på enkelte sætninger ikke tilstrækkeligt.

EDIT:Det er klart, indpakning af INSERT med BEGIN TRANSACTION og COMMIT løser det ikke, da standardisolationsniveauet for transaktioner stadig er READ COMMITTED , hvilket ikke er tilstrækkeligt. Bemærk, at indstilling af transaktionsisolationsniveauet til REPEATABLE READ er også ikke tilstrækkeligt. Den eneste måde at gøre ovenstående kode sikker på er at tilføje

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

på toppen. Dette forårsagede dog deadlocks nu og da i mine tests.

EDIT:Den eneste løsning, jeg fandt, er sikker og ikke producerer deadlocks (i hvert fald i mine tests) er eksplicit at låse tabellen udelukkende (standard transaktionsisolationsniveau er tilstrækkeligt her). Pas dog på; denne løsning kan dræbe ydeevne:

...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. 10 effektive måder at være mere produktiv på på arbejdspladsen

  2. Hvorfor bruge ikke null primær nøgle i TSQL?

  3. MySql forskel mellem to tidsstempler i dage?

  4. Introduktion til PostgreSQL