Questo semplice codice produce deadlock. Semplice programma di esempio incluso

Codice, notare che l’ordine dei valori è diverso. Quindi si alterna tra le file di chiusura:

static void Main( string[] args ) { List list = new List(); for(int i = 0; i  { using( NamePressDataContext db = new NamePressDataContext() ) { db.ExecuteCommand( @"update EBayDescriptionsCategories set CategoryId = Ids.CategoryId from EBayDescriptionsCategories join (values (7276, 20870),(240, 20870)) as Ids(Id,CategoryId) on Ids.Id = EBayDescriptionsCategories.Id" ); db.ExecuteCommand( @"update EBayDescriptionsCategories set CategoryId = Ids.CategoryId from EBayDescriptionsCategories join (values (240, 20870),(7276, 20870)) as Ids(Id,CategoryId) on Ids.Id = EBayDescriptionsCategories.Id" ); } } ); } 

Tabella def:

 CREATE TABLE [dbo].[EDescriptionsCategories]( [CategoryId] [int] NOT NULL, [Id] [int] NOT NULL, CONSTRAINT [PK_EDescriptionsCategories] PRIMARY KEY CLUSTERED ( [Id] ASC ) 

Eccezione:

 Transaction (Process ID 80) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. 

Il codice funziona solo con il suggerimento WITH (TABLOCK). È ansible non bloccare l’intera tabella solo per aggiornare solo quelle 2 righe in parallelo?

Le tue due istruzioni acquisiscono blocchi di riga in ordine diverso. È un classico caso di deadlock. È ansible risolvere questo problema assicurando che l’ordine dei blocchi sia sempre in ordine globale (ad esempio, ordinato per ID). Dovresti probabilmente fondere le due istruzioni UPDATE in una e ordinare l’elenco di ID sul client prima di inviarlo a SQL Server. Per molti tipici piani UPDATE questo funziona davvero bene (non è garantito, però).

In alternativa, si aggiunge la logica di riprova nel caso in cui SqlException.Number == 1205 rilevato un deadlock ( SqlException.Number == 1205 ). Questo è più elegante perché non richiede modifiche al codice più profonde. Ma i deadlock hanno implicazioni sulle prestazioni, quindi fatelo solo per bassi tassi di deadlock.

Se l’elaborazione parallela genera molti aggiornamenti, è ansible INSERT tutti gli aggiornamenti in una tabella temporanea (che può essere eseguita contemporaneamente) e al termine si esegue un grande UPDATE che copia tutti i singoli record di aggiornamento nella tabella principale. Basta modificare la sorgente di join nelle query di esempio.

Codice, notare che l’ordine dei valori è diverso. Quindi si alterna tra le file di chiusura

No, non si alterna. Acquisisce le serrature in due diversi ordini. Deadlock è garantito .

È ansible non … aggiornare solo quelle 2 file in parallelo?

Non è così. Quello che chiedi è la definizione di un punto morto. Qualcosa deve dare. La soluzione deve provenire dalla tua logica aziendale, non ci dovrebbero essere tentativi di elaborare lo stesso set di ID da transazioni distinte. Ciò significa che è tutto business specifico. Se non riesci a raggiungere questo objective, in pratica stai solo implorando un deadlock. Ci sono alcune cose che puoi fare, ma nessuna è a prova di proiettile e tutte vengono a caro prezzo. Il problema è più in alto nella catena.

Accetto con altre risposte per quanto riguarda il blocco.

La domanda più urgente è che cosa speri di ottenere da questo? C’è solo un cavo che quei comandi stanno viaggiando verso il basso.

In questo modo stai peggiorando le prestazioni complessive. Molto meglio fare il calcolo in parallelo ma serializzare (e possibilmente in gruppo) i tuoi aggiornamenti.