sql >> Database >  >> RDS >> Sqlserver

In tsql is een Insert met een Select-statement veilig in termen van gelijktijdigheid?

Zoals Paul schrijft:Nee, het is niet veilig , waarvoor ik empirisch bewijs wil toevoegen:Maak een tabel Table_1 met één veld ID en één record met waarde 0 . Voer vervolgens de volgende code gelijktijdig uit in twee Management Studio-queryvensters :

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

Voer vervolgens uit

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

Op mijn SQL Server 2008 één ID (662 ) is twee keer gemaakt. Het standaard isolatieniveau dat wordt toegepast op enkele instructies is dus niet voldoende.

EDIT:Het is duidelijk dat de INSERT met BEGIN TRANSACTION en COMMIT zal het niet oplossen, aangezien het standaard isolatieniveau voor transacties nog steeds READ COMMITTED . is , wat niet voldoende is. Merk op dat het instellen van het transactie-isolatieniveau op REPEATABLE READ is ook niet voldoende. De enige manier om de bovenstaande code veilig te maken is om toe te voegen

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

op de top. Dit zorgde echter af en toe voor impasses in mijn tests.

EDIT:De enige oplossing die ik heb gevonden die veilig is en produceert geen deadlocks (althans in mijn tests) is om de tabel expliciet exclusief te vergrendelen (standaard transactie-isolatieniveau is hier voldoende). Pas echter op; deze oplossing kan doden prestatie:

...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. pgDash Diagnostische alternatieven - PostgreSQL-querybeheer met ClusterControl

  2. Een inleiding tot datamining

  3. De schoonste manier om een ​​SQL-string in Java te bouwen

  4. PHP-bestand kan een deel van de code niet invoeren