2009-06-25 12 views
7

Sono parte di un team che crea un sito Web basato su ADO.NET. A volte abbiamo diversi sviluppatori e uno strumento di test automatico che lavora simultaneamente a una copia di sviluppo del database.Utilizzo di IsolationLevel.Snapshot ma DB sta ancora bloccando

Utilizziamo il livello di isolamento dello snapshot, che, per quanto ne so, utilizza la concorrenza ottimistica: anziché bloccarsi, spera il meglio e genera un'eccezione se si tenta di eseguire il commit di una transazione se le righe interessate sono state modificate da un'altra parte durante la transazione.

Per utilizzare il livello di isolamento dello snapshot che utilizziamo:

ALTER DATABASE <database name> 
SET ALLOW_SNAPSHOT_ISOLATION ON; 

e in C#:

Transaction = SqlConnection.BeginTransaction(IsolationLevel.Snapshot); 

noti che IsolationLevel di foto non è la stessa di READCOMMITTED Snapshot, che abbiamo anche provato, ma non sono attualmente in uso.

Quando uno degli sviluppatori entra in modalità di debug e sospende l'app .NET, terranno una connessione con una transazione attiva durante il debug. Ora, mi aspetto che questo non sia un problema - dopo tutto, tutte le transazioni utilizzano il livello di isolamento dello snapshot, quindi mentre una transazione viene messa in pausa, altre transazioni dovrebbero essere in grado di procedere normalmente poiché la transazione sospesa non contiene alcun blocco. Ovviamente, quando la transazione in pausa viene completata, è probabile che rilevi un conflitto; ma ciò è accettabile a condizione che altri sviluppatori e i test automatici possano procedere senza ostacoli.

Tuttavia, in pratica, quando una persona interrompe una transazione durante il debug, tutti gli altri utenti di DB che tentano di accedere alle stesse righe vengono bloccati nonostante l'utilizzo del livello di isolamento dello snapshot.

Qualcuno sa perché questo si verifica e/o come posso ottenere una concorrenza ottimistica (non bloccante)?

La risoluzione (uno sfortunato per me): Remus Rusanu ha notato che gli scrittori bloccano sempre altri scrittori; questo è supportato da MSDN - non viene fuori e lo dice, ma menziona solo sempre evitando i blocchi di lettore-scrittore. In breve, il comportamento che desidero non è implementato in SQL Server.

risposta

8

isolamento SNAPSHOT livello influisce, come tutti i livelli di isolamento, solo letture. Le scritture si stanno ancora bloccando a vicenda. Se ritieni che ciò che vedi siano blocchi di lettura, dovresti investigare ulteriormente e controllare i tipi di risorse e i nomi delle risorse su cui si verifica il blocco (wait_type e wait_resource in sys.dm_exec_requests).

Non consiglierei di apportare modifiche al codice per supportare uno scenario che coinvolge gli sviluppatori che fissano il debugger per i minuti alla fine. Se ritieni che questo scenario possa ripetersi nella produzione (ad es. Il client si blocca), allora è una storia diversa. Per ottenere ciò che desideri, devi ridurre al minimo le scritture ed eseguire tutte le scritture alla fine della transazione, in una singola chiamata che esegue il commit prima del reso. In questo modo nessun client può tenere bloccati X per un lungo periodo di tempo (non può bloccarsi mantenendo i blocchi X). In pratica questo è piuttosto difficile da eseguire e richiede molta disciplina da parte degli sviluppatori nel modo in cui scrivono il codice di accesso ai dati.

+0

Questo comportamento è improbabile in produzione. D'altra parte, la versione di sviluppo è abbastanza importante, e sarei abbastanza disposta a apportare modifiche al codice se questo smorzerà lo sviluppo. Sfortunatamente, uno stile "svn-esque" di blocco (speranza per il meglio e semplicemente fallimento in conflitto) non sembra essere implementato. La possibilità di avere transazioni di lunga durata e complesse senza bloccare tutte le piccole transazioni sarebbe comunque utile - così come, usiamo meno transazioni che sono ideali solo per evitare il blocco. –

+1

Non c'è un proiettile d'argento. Ma se ti trovi spesso bloccato in scrittura e scrittura dovresti considerare il motivo per cui ciò si verifica, perché le diverse 'richieste' causano aggiornamenti degli stessi dati. Forse è possibile partizionare meglio l'applicazione, ridurre la probabilità di sovrapposizione. Forse alcuni aggiornamenti possono essere posticipati, inseriti in una tabella di lavoro durante la transazione dell'utente (enque/dequeue può essere reso libero da blocchi, con cura) e successivamente elaborati da processi batch dedicati. Assicurati inoltre che tutte le transazioni blocchino solo il minimo necessario (nessun blocco di pagina/tabella, nessuna escalation, nessuna scansione di tabelle inutili). –

2

Hai guardato i blocchi quando uno sviluppatore interrompe la transazione? Inoltre, l'attivazione del livello di isolamento dello snapshot non ha molto effetto. Hai impostato ALLOW_SNAPSHOT_ISOLATION ON?

Ecco i passaggi:

ALTER DATABASE <databasename> 
SET READ_COMMITTED_SNAPSHOT ON; 
GO 

ALTER DATABASE <database name> 
SET ALLOW_SNAPSHOT_ISOLATION ON; 
GO 

Dopo che il database è stato abilitato per l'isolamento dello snapshot, gli sviluppatori e gli utenti devono quindi richiedere che le loro transazioni essere eseguiti in questa modalità istantanea. Questo deve essere fatto prima di iniziare una transazione, sia per una direttiva sul lato client per l'oggetto delle transazioni ADO.NET o all'interno del loro query Transact-SQL utilizzando la seguente dichiarazione:

SET TRANSACTION ISOLATION LEVEL SNAPSHOT 

Raj

+0

Il database ha allow_snapshot_isolation attivo. In caso contrario, si verificherà un'eccezione immediata; non è possibile impostare il livello di isolamento su snapshot quando allow_snapshot_isolation è disattivato (ad esempio, l'impostazione del livello di isolamento non fallisce automaticamente). aggiornerò il post per riflettere i comandi esatti necessari, grazie! –

Problemi correlati