10

seguente dichiarazione:Snapshot transazione di isolamento interrotta a causa di aggiornare conflitto

INSERT INTO dbo.Changes([Content], [Date], [UserId], [CompanyId]) 
    VALUES (@1, @2, @3, @4); 
SELECT @@identity; 

mi dà questo errore SQL 3960:

transazione di isolamento dello snapshot interrotta a causa di aggiornare il conflitto. L'utente non può utilizzare l'isolamento dell'istantanea per accedere alla tabella "dbo.Companies" direttamente o indirettamente nel database "myDatabase" per aggiornare, eliminare o inserire la riga che è stata modificata o eliminata da un'altra transazione. Riprovare la transazione o modificare il livello di isolamento per l'istruzione di aggiornamento/eliminazione .

Per quanto ho capito, dal messaggio di errore, non è necessario aggiornare, cancellare, o inserire la tabella dbo.Companies durante il tempo un'altra connessione sta modificando dbo.Companies.

Ma perché si verifica quando ero inserendo una nuova riga di un'altra tabella dbo.Changes (che ha chiave esterna a dbo.Companies) e non mi eliminazione della riga riferimento nella dbo.Companies, ma ero solo aggiornando riga dbo.Companies e non il primario chiave? Questo dovrebbe funzionare ok, non dovrebbe? (Si tratta di un bug in SQL Server?)

UPDATE:

tabelle si presenta come segue:

dbo.Changes([Id] int PK, [Content] nvarchar, 
    [Date] datetime, [UserId] int, [CompanyId] int -> dbo.Companies.[Id]) 
dbo.Companies([Id] int PK, [Name] nvarchar) 

Secondo aggiornamento sta facendo:

UPDATE dbo.Companies WHERE [Id] = @1 SET [Name] = @2; 

risposta

5

Sembra SQL Il server acquisirà i blocchi di aggiornamento in qualsiasi record che deve leggere anche se non lo modifica.

Maggiori informazioni microsoft.public.sqlserver.server thread:

Senza un indice di supporto sul CustomerContactPerson, la dichiarazione

DELETE FROM WHERE ID = ContactPerson @ID;

richiederà una "corrente" di lettura di tutte le righe CustomerContactPerson per garantire che non ci sono righe CustomerContactPerson che fanno riferimento alla ContactPerson riga eliminata. Con l'indice, il DELETE può determinare che non ci sono righe correlate in CustomerContactPerson senza leggere le righe interessate dall'altra transazione.

Inoltre, in uno snapshot transazione il modello per la lettura dei dati, che si sta per girare intorno e aggiornamento è quello di prendere un UPDLOCK quando si legge. Ciò assicura che esegua l'aggiornamento sulla base dei dati "correnti", non dei dati "coerenti" (istantanea) , e che quando si emette il DML, i dati non verranno bloccati e si vince " t sovrascrivendo involontariamente un'altra modifica della sessione .

La correzione per noi era aggiungendo indici per le chiavi esterne

Nel tuo esempio, ho il sospetto aggiungendo un indice per Changes.CompanyId aiuterà. Non sono sicuro che questa sia una soluzione reale. L'ottimizzatore di SQL Server può scegliere di non utilizzare l'indice?

+0

Grazie per i suggerimenti, ma non sembra essere d'aiuto. –

+0

Le due istruzioni (INSERT e UPDATE) si riferiscono allo stesso cliente? Se è così, siamo sfortunati per quanto ne so. –

+0

Sì, inserire sta utilizzando l'id della società attualmente in aggiornamento. –

3

SQL Server può vedere un aggiornamento a una tabella dipendente che POTREBBE modificare il comportamento dell'inserto ... mi sembra giusto come SQL non può indovinare quale altra logica potrebbe essere dipendente o n [Nome] di colonna (trigger ecc)

se le applicazioni implementare la logica di tentativi situazione di stallo è possibile modificarli per trattare l'errore non è 3960 lo stesso errore non 1205 e automaticamente riprovare ...

+0

Si fa un buon punto .... eccetto, ancora non capisco perché avere un indice non univoco, non univoco sulla colonna della chiave esterna della tabella correlata è sufficiente per evitare che ciò accada, cioè non è il caso che potrebbe ancora modificare il comportamento dell'inserto, anche con l'indice? – Kram

+0

@Kram Suppongo che l'indice aiuti la granularità. Il motore sa che una tabella dipendente deve essere bloccata ma senza un indice può provare a bloccare l'intera tabella invece una singola riga – jean

Problemi correlati