2009-10-06 17 views
29

Ho visto molti esempi del suggerimento HOLDLOCK utilizzato in combinazione con UPDLOCK (like this). Tuttavia, per questi suggerimenti, Microsoft's documentation sembra che HOLDLOCK debba essere ridondante, poiché UPDLOCK persiste già fino al termine della transazione. (Inoltre sembra che HOLDLOCK si applichi solo ai blocchi condivisi.)Che effetto ha HOLDLOCK su UPDLOCK?

In che modo HOLDLOCK influisce sulla query, se non del tutto?

risposta

59

Ha un grande impatto.

Il blocco di aggiornamento richiede un blocco di aggiornamento sulla riga, l'aggiornamento di Intent sulla pagina e un blocco condiviso sulla tabella/database.

Ciò non impedisce ad altre query di accedere ai dati all'interno della tabella, poiché i blocchi sulla pagina/database sono puramente blocchi di condivisione. Semplicemente non possono interferire con i blocchi contro la singola riga/pagina/tabella tentando di eseguire un'operazione che contraddirebbe i blocchi. Se ciò si verificava, la richiesta si accodava dietro i blocchi correnti e aspettava che fosse disponibile prima che potesse procedere.

Utilizzando holdlock, la query viene forzata per essere serializzata, bloccando la tabella esclusivamente fino al completamento dell'azione. Ciò impedisce a chiunque di leggere la tabella a meno che non venga usato il suggerimento nolock, consentendo una lettura potenzialmente sporca.

Per vedere l'effetto, generare una tabella di esempio 'pippo' e inserire alcuni dati cestino in esso.

begin tran 

select * from foo with (updlock) 
where tableid = 1 
-- notice there is no commit tran 

Aprire un'altra finestra e provare:

select * from foo 

Le righe tornano, ora il commit della transazione query originale. Re-eseguirlo alterata da utilizzare HOLDLOCK così:

begin tran 

select * from foo with (updlock, holdlock) 
where tableid = 1 

Torna alla all'altra finestra e provare selezionare nuovamente i dati, la query non restituirà i valori dal momento che è bloccata dal blocco esclusivo. Conferma la transazione sulla prima finestra e i risultati della seconda query appariranno poiché non è più bloccato.

Il test finale consiste nell'utilizzare il nolock, eseguire nuovamente la transazione utilizzando updlock e holdlock. quindi eseguire il seguente nella seconda finestra:

select * from foo (nolock) 

I risultati torneranno automaticamente, dal momento che avete accettato il rischio di una lettura sporca (leggi non impegnati).

Quindi è visto avere un grande impatto, nel senso che si stanno forzando le azioni su quel tavolo per essere serializzate che potrebbero essere ciò che si desidera (a seconda dell'aggiornamento in corso) o creerà un collo di bottiglia molto grande su quel tavolo . Se tutti lo facessero su una tabella occupata con transazioni di lunga durata, causerebbero ritardi significativi all'interno di un'applicazione.

Come tutte le funzionalità SQL, se utilizzate correttamente possono essere potenti, ma l'utilizzo errato di una funzionalità/suggerimento può causare problemi significativi. Preferisco utilizzare i suggerimenti come ultima risorsa per quando devo eseguire l'override del motore, non come approccio predefinito.

Modifica come richiesto: Testato in SQL 2005, 2008, 2008R2 (Tutte le imprese) - tutti installati su quasi tutte le impostazioni predefinite, database di test creato utilizzando tutti i valori predefiniti (è stato inserito solo il nome del DB).

+0

ottima risposta, grazie – marijne

+0

bella spiegazione, che aiuta molto! – Mercurybullet

+0

@Darren - Ho eseguito il rollback della modifica apportata, nessun blocco non è l'impostazione predefinita e la seconda selezione non dovrebbe richiedere un blocco di aggiornamento. – Andrew

12

è corretta di risposta di Andrew come da documentazione di MSDN, tuttavia ho provato contro 2008R2 e il 2012 e non sto vedendo questo comportamento quindi per favore mettiti alla prova

Il comportamento che sto vedendo è la seguente:

Prima eseguilo su un database di gioco.

CREATE TABLE [dbo].[foo](
    [tableid] [int] IDENTITY(1,1) NOT NULL, 
    [Col2] [varchar](100) NOT NULL, 
    CONSTRAINT [PK_foo] PRIMARY KEY CLUSTERED 
    (
     [tableid] ASC 
    ) 
) 

... e mettere un paio di righe in

Ora incollare questo codice in due schede di query (modificare il testo 'scheda uno' nella scheda due):.

begin tran 

select * from foo with (UPDLOCK, HOLDLOCK) 
where tableid = 1 

UPDATE foo SET Col2 = 'tab one' 
where tableid = 1 

commit tran 

E mettere questo in un'altra scheda 3.:

select * from foo 
where tableid = 1 
  1. Assicurati di puntare il tuo database di gioco in cui si trova la tabella.

  2. Evidenziare tutto prima la dichiarazione di aggiornamento in scheda 1 ed eseguire.

  3. Fare lo stesso nella scheda la scheda 2 NON verrà completata ed è ancora in esecuzione.

  4. Ora eseguire il semplice SELECT nella scheda 3nel mio ambiente che completa.

  5. Evidenziare l'istruzione di aggiornamento in scheda 1 ed eseguirlo (non faccio il commit ancora), si vedrà scheda 2 è ancora in esecuzione.

  6. Vai avanti ed eseguire il commit in scheda 1 ... scheda 2 ora completare l'select ... è possibile eseguire il resto.

+0

A quale versione di SQL Server è stata eseguita questa esecuzione? se 2012 allora il comportamento potrebbe essere cambiato, ma il holdlock 2005/2008/2008R2 lo forzerebbe in modalità serializzabile e bloccherebbe qualsiasi altra cosa dal prendere un blocco condiviso - che è ciò che la selezione 'semplice' tenterà di emettere. – Andrew

+1

Un'altra possibilità, se l'isolamento basato sul controllo delle versioni delle righe è attivato - quando l'isolamento basato sul controllo delle versioni delle righe è attivo, la selezione "semplice" non emetterà un blocco condiviso, solo un blocco Sch-S, che impedirebbe il blocco, sebbene quel livello di isolamento non è il default nel 2008. Sarà interessante identificare la differenza nei test. – Andrew

+0

@Andrew and Darren: modifica i tuoi rispettivi post e nota quali versioni di SQL Server hai * testato * le tue soluzioni su. I collegamenti che descrivono eventuali cambiamenti nel comportamento predefinito (o qualsiasi impostazione che hai fatto) sarebbero anche apprezzati =) –

Problemi correlati