2012-09-26 6 views
48

Mi chiedo quale sia il vantaggio di utilizzare SELECT WITH (NOLOCK) su una tabella se le uniche altre query che interessano tale tabella sono le query SELECT.Informazioni su LOCKS di SQL Server su query SELECT

Come viene gestito da SQL Server? Una query SELECT bloccherebbe un'altra query SELECT?

Utilizzo SQL Server 2012 e Linq-to-SQL DataContext.

(EDIT)

A proposito di prestazioni:

  • Sarebbe un 2 ° SELECT dovuto aspettare per un 1 ° SELECT per finire se si utilizza una bloccato SELECT?
  • Contro uno SELECT WITH (NOLOCK)?

Grazie.

risposta

111

Un SELECT in SQL Server porrà un blocco condiviso su una riga della tabella - ed una seconda SELECT richiederebbe anche un blocco condiviso, e questi sono compatibili tra loro.

Quindi nessuno SELECT non può bloccare un altro SELECT.

Il suggerimento di query WITH (NOLOCK) è utilizzato per poter leggere i dati che sono in fase di inserimento (con un'altra connessione) e che non è stato ancora eseguito il commit.

Senza questo hint per la query, un SELECT potrebbe essere bloccato la lettura di un tavolo da un'istruzione corso INSERT (o UPDATE) che pone un esclusiva blocco sulle righe (o, eventualmente, un tavolo intero), fino transazione dell'operazione è stato commesso (o arrotolato).

Il problema del suggerimento WITH (NOLOCK) è: potresti leggere le righe di dati che non verranno inserite affatto, alla fine (se la transazione INSERT viene ripristinata), ad esempio il tuo es. il report potrebbe mostrare dati che non sono mai stati realmente inseriti nel database.

C'è un altro suggerimento per le query che potrebbe essere utile - WITH (READPAST). Questo indica al comando SELECT di saltare solo le righe che tenta di leggere e che sono bloccate esclusivamente. SELECT non bloccherà e non leggerà alcun dato "non impegnativo" non impegnato, ma potrebbe saltare alcune righe, ad es. non mostrare tutte le tue righe nella tabella.

+1

Bella risposta, grazie mille! Ci sarebbe un impatto (su centinaia di query 'SELECT') per usare' WITH (NOLOCK) 'senza motivo? –

+1

Usiamo con nolock nel 99,5% dei nostri selezionati, senza scherzo. Se un amministratore sta aggiornando un record utente, non si vuole che questo causi il fatto che il report resti lì e aspetti che l'intera transazione distribuita finisca. Quindi i loro vecchi dati appaiono sul rapporto. Che importa? Se il rapporto fosse stato eseguito un secondo prima, si tratta degli stessi dati che sarebbero stati lì con il rowlock. L'unico posto che preoccupa sono i dati che non sono stati ancora impegnati. Se stai mostrando "ordini nell'ultima ora" che potrebbero potenzialmente essere un problema, ma un piccolo, piccolo problema rispetto ai guadagni di velocità/concorrenza. –

+2

Inoltre, poiché "report" è stato buttato fuori come esempio, i report sono in genere per un periodo di tempo che non corrisponde agli ultimi 5 minuti. Segnalazione sui dati del mese scorso con nolock - beh, non è che i dati arriveranno al rollback un mese dopo. –

1

selezionare senza blocco - selezionerà i record che possono/non possono essere inseriti. leggerai un dato sporco

ad esempio - consente di dire una transazione inserire 1000 righe e quindi non riesce.

quando si seleziona - verranno visualizzate le 1000 righe.

+0

Ma cosa succede se nessun record è destinato ad essere inserito in tale tabella, il BLOCCO NO è ancora rilevante? –

+0

no non lo è. poiché read utilizza un blocco condiviso che può essere acquisito da più di 1 sessione. non c'è modo di ottenere dati sporchi. –

+0

E su una performance POV? –

6

Al mio lavoro, abbiamo un sistema molto grande che funziona su molti PC allo stesso tempo, con tabelle molto grandi con centinaia di migliaia di righe e, a volte, molti milioni di righe.

Quando si effettua un SELEZIONA su un tavolo molto grande, diciamo che si desidera conoscere ogni transazione effettuata da un utente negli ultimi 10 anni e che la chiave primaria della tabella non è costruita in modo efficiente, la query potrebbe richiedere diversi minuti per l'esecuzione.

Quindi, la nostra applicazione potrebbe essere in esecuzione su più PC dell'utente allo stesso tempo, accedendo allo stesso database. Quindi, se qualcuno tenta di inserire nella tabella che l'altro SELECT sta leggendo (nelle pagine che SQL sta cercando di leggere), allora può verificarsi un LOCK e le due transazioni si bloccano a vicenda.

Abbiamo dovuto aggiungere un "NO LOCK" alla nostra istruzione SELECT, perché era un enorme SELECT su un tavolo che è utilizzato molto da molti utenti allo stesso tempo e abbiamo avuto LOCKS tutto il tempo.

Non so se il mio esempio è abbastanza chiaro? Questo è un esempio di vita reale.

+0

Grazie per l'esempio, ma mi sto chiedendo solo le query SELECT che interessano altre query SELECT (su quella stessa tabella) .. –

+1

Non lo faranno, ma un'istruzione select potrebbe essere parte della transazione che include un aggiornamento . Aggiorna tbl set x = (seleziona max (y) da tbl) dove z = (seleziona min (a) da tbl). Se hai una selezione simultanea di z da tbl beh, le altre selezioni non la bloccano, ma l'aggiornamento è. –

+0

Avevo esattamente questo problema che una selezione in esecuzione prolungata stava bloccando i miei inserti – nojetlag

22

Durante le prestazioni continui a concentrarti su selezionare.
Shared non blocca le letture.
Aggiornamento blocchi bloccati condivisi.
Se si dispone di centinaia di blocchi condivisi, è necessario attendere un aggiornamento per ottenere un blocco esclusivo in quanto deve attendere la cancellazione dei blocchi condivisi.

Per impostazione predefinita, selezionare (leggi) accetta un blocco condiviso.
I blocchi condivisi (S) consentono alle transazioni concorrenti di leggere (SELEZIONARE) una risorsa.
Un blocco condiviso come nessun effetto su altri selezioni (1 o 1000).

La differenza è il modo in cui il nolock rispetto agli effetti di blocco condiviso aggiorna o inserisce un'operazione.

Nessun'altra transazione può modificare i dati mentre i blocchi condivisi (S) esistono sulla risorsa.

Un blocco condiviso blocca un aggiornamento!
Ma nolock non blocca un aggiornamento.

Questo può avere un impatto enorme sulle prestazioni degli aggiornamenti. Influisce anche sugli inserti.

La lettura sporca (nolock) sembra solo sporca. Non otterrai mai dati parziali. Se un aggiornamento sta cambiando John in Sally, non otterrai mai Jolly.

Io uso molto i blocchi condivisi per la concorrenza. I dati sono obsoleti non appena vengono letti. Una lettura di John che cambia in Sally il prossimo millisecondo sono dati obsoleti. Una lettura di Sally che viene riportata indietro di John il secondo millisecondo è dati obsoleti. Questo è al millisecondo. Ho un dataloader che richiede 20 ore per essere eseguito se gli utenti stanno prendendo i blocchi condivisi e 4 ore per l'esecuzione è che gli utenti non stanno prendendo alcun blocco. In questo caso, i blocchi condivisi causano 16 ore di dati obsoleti.

Non utilizzare nolocks errati. Ma loro hanno un posto. Se si sta per tagliare un segno di spunta quando un byte è impostato su 1 e quindi impostarlo su 2 quando il controllo è tagliato, non un tempo per un arresto.

+1

Grazie. Vediamo caratteristiche di performance simili. Il nostro sito non funzionerebbe se avessimo bisogno di blocchi per le letture e l'impatto di non averlo nella maggior parte dei casi è insignificante. –

+0

@BrianWhite Grazie. Qualcuno lo capisce. E prendo un sacco di blocchi del tavolo durante l'aggiornamento e inserire. Entra, fallo e scendi è il mio approccio. – Paparazzi

+1

La lettura sporca (nolock) sembra solo sporca. Non otterrai mai dati parziali. Se un aggiornamento sta cambiando John in Sally, non otterrai mai Jolly. - leggiamo John, giusto? – MonsterMMORPG

2

Il SELECT WITH (NOLOCK) consente la lettura di dati non salvati, che equivale ad avere il livello di isolamento READ UNCOMMITTED impostato nel database. La parola chiave NOLOCK consente un controllo a grana fine piuttosto che impostare il livello di isolamento sull'intero database.

Wikipedia ha un articolo utile: Wikipedia: Isolation (database systems)

È anche discusso a lungo in altri articoli StackOverflow.

+0

Grazie rghome per le informazioni aggiuntive fornite. –

+0

Ecco perché preferisco usare l'hint 'READUNCOMMITTED' (un alias per' NOLOCK'), * quando * tale è un caso d'uso valido. In questo modo, l'operazione effettiva, che * non è * realmente "senza serrature", meno chiara. – user2864740

7

Devo aggiungere un commento importante. Tutti menzionano che NOLOCK legge solo dati sporchi. Questo non è preciso. È anche possibile che si ottenga la stessa riga due volte o che l'intera riga venga saltata durante la lettura. Il motivo è che potresti chiedere alcuni dati nello stesso momento in cui SQL Server sta riequilibrando il b-tree.

controllare un altro thread

https://stackoverflow.com/a/5469238/2108874

http://www.sqlmag.com/article/sql-server/quaere-verum-clustered-index-scans-part-iii.aspx)

Con l'hint NOLOCK (o l'impostazione del livello di isolamento della sessione per READ UNCOMMITTED) si raccontano SQL Server che non si aspettati coerenza, quindi non ci sono garanzie. Ricordare però che i "dati incoerenti" non significano solo che si potrebbero vedere modifiche non eseguite che sono state successivamente ripristinate o cambiamenti di dati in uno stato intermedio della transazione. Significa anche che in una query semplice che analizza tutti i dati di tabella/indice, SQL Server potrebbe perdere la posizione di scansione, oppure si potrebbe finire per ottenere la stessa riga due volte.