2013-05-14 11 views
19

Assumendo:Un'operazione INSERT può provocare un deadlock?

  • Sto usando REPEATABLE_READ o di isolamento delle transazioni SERIALIZABLE (serrature ottenere mantenuto ogni volta che accedere a una riga)
  • Stiamo parlando di più thread di accesso a più tavoli contemporaneamente.

Ho le seguenti domande:

  1. E 'possibile per un'operazione INSERT per provocare una situazione di stallo? In tal caso, fornire uno scenario dettagliato che mostri come può verificarsi un deadlock (ad esempio, il thread 1 esegue questa operazione, il thread 2 lo fa, ..., deadlock).
  2. Per i punti bonus: rispondere alla stessa domanda per tutte le altre operazioni (ad esempio SELECT, UPDATE, DELETE).

UPDATE: 3. Per i punti bonus super: come posso evitare una situazione di stallo nel seguente scenario?

tavoli proprio:

  • autorizzazioni [id BIGINT PRIMARY KEY]
  • aziende [id BIGINT PRIMARY KEY, name VARCHAR(30), permission_id BIGINT NOT NULL, FOREIGN KEY (permission_id) REFERENCES permissions(id))

ho creare una nuova società come segue:

  • INSERT INTO permessi; - Inserts permissions.id = 100
  • INSERIRE IN aziende (nome, permission_id) VALUES ('Nintendo', 100); - Inserti companies.id = 200

cancello una società come segue:

  • SELEZIONA permission_id da società WHERE id = 200; - restituisce permission_id = 100
  • ELIMINA DA società DOVE id = 200;
  • ELIMINA DA autorizzazioni DOVE id = 100;

Nell'esempio precedente, l'ordine di blocco INSERT è [autorizzazioni, aziende] mentre l'ordine di blocco DELETE è [aziende, autorizzazioni]. C'è un modo per correggere questo esempio per l'isolamento REPEATABLE_READ o SERIALIZABLE?

+0

Uno scenario definito come un singolo utente (in una singola transazione) inserimento, selezione e la cancellazione non sta per causare un deadlock. –

+0

@CleverIdeaWidgetry, ho chiarito la domanda per riflettere sul fatto che stiamo parlando di più thread e tabelle. – Gili

+0

La risposta alla tua domanda di base "può?" è sì - come altri hanno già detto. C'è qualche ostacolo che ti impedisce di testare il tuo scenario da solo? –

risposta

22

In genere tutte le modifiche possono causare un deadlock e la selezione non lo consentirà (consultare più avanti). Quindi

  1. No, non puoi ignorarli.
  2. Puoi in qualche modo ignorare la selezione in base al tuo database e alle impostazioni, ma gli altri ti daranno deadlock.

Non hai nemmeno bisogno di più tavoli.

Il modo migliore per creare un deadlock è fare la stessa cosa in un ordine diverso.

esempi di SQL Server:

create table A 
(
    PK int primary key 
) 

Sessione 1:

begin transaction 
insert into A values(1) 

Sessione 2:

begin transaction  
insert into A values(7) 

Sessione 1:

delete from A where PK=7 

Sessione 2:

delete from A where PK=1 

Si otterrà una situazione di stallo. In questo modo, le eliminazioni dimostrate delle eliminazioni & possono bloccarsi.

aggiornamenti sono simili:

Sessione 1:

begin transaction  
insert into A values(1) 
insert into A values(2) 
commit 

begin transaction 
update A set PK=7 where PK=1 

Sessione 2:

begin transaction 
update A set pk=9 where pk=2  
update A set pk=8 where pk=1 

Sessione 1:

update A set pk=9 where pk=2 

Deadlock!

SELECT non dovrebbe mai deadlock ma su alcuni database lo farà perché i blocchi che utilizza interferiscono con letture coerenti. Questo però è solo un pessimo motore di database.

SQL Server non si blocca su SELECT se si utilizza ISOLAMENTO SNAPSHOT. Oracle & Penso che Postgres non si bloccherà mai su SELECT (a meno che tu non abbia FOR UPDATE che riserva chiaramente comunque un aggiornamento).

Quindi, in pratica, penso che tu abbia alcune ipotesi errate.Penso di aver dimostrato:

  1. aggiornamenti possono causare situazioni di stallo
  2. Elimina possono causare situazioni di stallo
  3. inserti possono causare situazioni di stallo
  4. Non è necessario più di una tabella
  5. È fai necessità più di una sessione

Dovrai solo prendere la parola su SELECT;) ma dipenderà da il nostro DB e le impostazioni.

+0

In primo luogo, grazie per avere la decenza di rispondere alla domanda correttamente :) In secondo luogo, ho aggiunto una terza domanda per la tua recensione. Si prega di consultare la domanda aggiornata. – Gili

+0

Non sembra che funzioni. Non è possibile eliminare l'autorizzazione prima della società in quanto è referenziata dall'FK. – LoztInSpace

+0

Ho corretto la domanda n. 3. Per favore riprova. – Gili

0

Supponiamo di avere due relazioni A e B e due utenti X e Y. La tabella A è bloccata in scrittura dall'utente X e tabella B è bloccata in scrittura da Y. Poi la query seguente vi darà una dead lock, se usato da entrambe le utenti X e Y.

Select * from A,B 

Quindi, chiaramente un'operazione Select può causa un deadlock se le operazioni di join che coinvolgono più di una tabella ne fanno parte. Le operazioni di inserimento e cancellazione di solito coinvolgono singole relazioni. Quindi non possono causare stallo.

+0

Si supponga che tutte le operazioni coinvolgano più tabelle (come dimostrato nell'esempio) perché chiaramente non è possibile ottenere deadlock senza farlo. A tal fine, quali operazioni possono causare deadlock e quali no. Finora hai dimostrato come 'SELECT' ** può ** causare deadlock. Parliamo del resto – Gili

+0

Se esiste un vincolo di chiave esterna tra le relazioni A e B, A e B sono bloccati rispettivamente dagli utenti X e Y, quindi si potrebbe ottenere un deadlock. – Deepu

+0

Non hai risposto alla mia domanda. Sto chiedendo su ** tutte ** le operazioni SQL, non solo su 'SELECT'. Sono principalmente interessato a 'INSERT', ma mi aspetto che anche tu discuti di tutti gli altri tipi di operazione. – Gili

1

Oltre alla risposta di LoztInSpace, inserts può causare deadlock anche senza presenza deletes o updates. Tutto ciò di cui hai bisogno è un indice univoco e un ordine di operazioni invertite.

Esempio in Oracle:

create table t1 (id number); 
create unique index t1_pk on t1 (id); 

--thread 1 : 
insert into t1 values(1); 
--thread 2 
insert into t1 values(2); 
--thread 1 : 
insert into t1 values(2); 
--thread 2 
insert into t1 values(1); -- deadlock ! 
+0

E quale soluzione? – Akvel

+1

Penso che la soluzione più semplice (ma non sempre possibile) sarebbe quella di ordinare le righe prima di inserirle. –

+0

Perché ciò causerebbe un deadlock invece di una violazione del vincolo e il rollback sul commit del thread 2? –