2009-09-16 13 views
5

ho acceso l'isolamento dello snapshot nel mio database utilizzando il seguente codiceSnapshot su, ancora situazioni di stallo, ROWLOCK

ALTER DATABASE MyDatabase 
SET ALLOW_SNAPSHOT_ISOLATION ON 

ALTER DATABASE MyDatabase 
SET READ_COMMITTED_SNAPSHOT ON 

e sbarazzato fuori un sacco di situazioni di stallo.

Ma il mio database produce ancora deadlock, quando ho bisogno di eseguire uno script ogni ora per ripulire oltre 100.000 righe.

  • C'è un modo per evitare deadlock nel mio script di pulizia, devo impostare ROWLOCK in modo specifico in quella query?
  • C'è un modo per aumentare il numero di blocchi a livello di riga utilizzati da un database?
  • Come vengono promossi i blocchi? Dal livello della riga al livello della pagina fino al livello della tabella?

Il mio script di eliminazione è piuttosto semplice:

delete statvalue 
from statValue, 
(select dateadd(minute,-60, getdate()) as cutoff_date) cd 
where temporaryStat = 1 
and entrydate < cutoff_date 

In questo momento sto cercando una soluzione rapida, ma una soluzione a lungo termine sarebbe ancora più bello.

Grazie mille, Patrikc

+0

È possibile pubblicare le informazioni di traccia deadlock? Vedere http://www.dalun.com/blogs/10.13.2006.htm per un esempio di come farlo. – Justin

+0

statValue ha un indice su entryDate? Hai esaminato il piano di query. Mi chiedo se stai facendo una scansione del tavolo. – automatic

+0

indovina che qui non c'è spazio sufficiente per postare la traccia di deadlock qui ... entrytDate non ha un indice, sto usando StatValueID come indice. c'è un indice di ricerca nel piano di esecuzione e anche un indice di ricerca in cluster. – Patto

risposta

0

Il modo per farlo per ridurre (o evitare) deadlock è quello di eliminare in lotti con una breve attesa tra ogni lotto (usando WAITFOR DELAY)

Inoltre, deadlock può essere mitigato avendo un indice di copertura.

Questo codice richiede alcune dichiarazioni, ed è solo a titolo di esempio (Esegui a proprio rischio!).

SELECT @intRowCount = 1, 
    @intErrNo = 0 

DECLARE @cutoff_date DATETIME 

SET @cutoff_date = dateadd(minute,-60, getdate()) 

SELECT @intRowsToDelete = COUNT(*) -- Number of rows to be deleted 
FROM dbo.statValue 
WHERE temporaryStat = 1 
AND entrydate < @cutoff_date 

WHILE @intRowCount > 0 AND @intErrNo = 0 
BEGIN 

    SET ROWCOUNT @DEL_ROWCOUNT 

    delete statvalue 
    FROM dbo.statValue 
    WHERE temporaryStat = 1 
    AND entrydate < @cutoff_date 

    SELECT @intErrNo = @@ERROR, @intRowCount = @@ROWCOUNT 

    SET ROWCOUNT 0 -- Reset batch size to "all" 

    SELECT @intRowsToDelete = @intRowsToDelete - @intRowCount 

    WAITFOR DELAY '000:00: 
END 

Ho anche incluso il suggerimento di John di non calcolare ripetutamente i criteri dell'intervallo di date.

+0

Non fare affidamento sul conteggio delle righe impostato. Ha problemi e sta per diventare obsoleto. Basta eliminare la parte superiore in un ciclo e interrompere @@ rowcount = 0: 'while (1 = 1) inizia delete top (@del_count) dove ...; se @@ rowcount = 0 interruzione; FINE'. –

+0

Da BOL: "L'utilizzo di SET ROWCOUNT non influirà sulle istruzioni DELETE, INSERT e UPDATE nella prossima versione di SQL Server" –

+0

@Rusus Rusanu: Cheers. Me ne ero completamente dimenticato. Anche se sembra dubbio che sarà rimosso ... –

0

Si prega di ri-scrivere il vostro query di eliminazione in questo modo:

DECLARE @cutoff_date DATETIME 

SET @cutoff_date = dateadd(minute,-60, getdate()) 

delete statvalue 
from statValue 
where temporaryStat = 1 
and entrydate < @cutoff_date 

si vedrà una riduzione dei costi nel vostro piano di esecuzione

6

isolamento SNAPSHOT può solo attenuare (alcune) delle situazioni di stallo che coinvolgono letture, ma non fa assolutamente nulla per evitare i deadlock write vs. write. Se si generano 100k + righe all'ora, si tratta di ~ 30 inserimenti al secondo, pertanto la scansione dell'eliminazione è praticamente in conflitto con altre operazioni di scrittura. Se tutto ciò che fai è Inserisci, non aggiorna mai, quindi il blocco di eliminazione, ma non il deadlock al blocco a livello di riga, ma poiché la tabella è abbastanza grande e l'eliminazione esegue una scansione, il motore sceglierà probabilmente un blocco di pagina per l'eliminazione, quindi probabilmente lo stallo si ottiene.

w/o un indice sulla data di ingresso la cancellazione non ha scelta ma per eseguire la scansione dell'intera tabella. Questo tipo di tabelle che vengono frequentemente inserite nella parte superiore e cancellate in fondo sono in effetti delle code e il tuo deve organizzarle entro la data di entrata. Ciò significa che data di ingresso dovrebbe probabilmente essere la chiave più a sinistra nell'indice cluster. Questa organizzazione consente una chiara separazione degli inserti che si verificano all'estremità della tabella rispetto alle eliminazioni che si verificano all'altra estremità. Ma questo è un cambiamento piuttosto radicale, specialmente se si usa lo statvalueid per leggere questi valori. Immagino che adesso abbiate un indice cluster basato su un campo autoincremento (StatValueId). Suppongo anche che la data di entrata e lo statvalueid siano correlati.Se entrambe le ipotesi sono vere, allora si dovrebbe eliminare base di don lo statvalueid: trovare il più grande id che è sicuro da eliminare, quindi eliminare tutto su l'indice cluster sinistra di questo id:

declare @statvalueidmax int; 
select @statvalueidmax = max(statvalueid) 
from statvalue with (readpast) 
where entrydate < dateadd(minute,-60, getdate()); 

delete statvalue 
where statvalueid <= @statvalueidmax; 

Ci sono una serie di ipotesi Ho fatto, potrebbero essere sbagliati. Ma il succo dell'idea è che devi separare gli inserti dalle eliminazioni in modo che non si sovrappongano.

+0

Mi piace questa idea e proverò questo, ma non sono sicuro se questo mi aiuterà con i deadlock che vengono creati. In futuro, mi aspetto ancora più dati in questa tabella. – Patto

+1

Ci sono molti fattori in gioco e ho poche piccole informazioni. Ma dovresti provare ad immaginare il tavolo come una linea (ordine dalla tua chiave clandestina da sinistra a destra): il tuo lavoro batch orario si allontana sul lato sinistro della linea, inserisce lookus e gli aggiornamenti si verificano nell'hotspot di attività corrente, in il lato destro. Se i due non si incontrano, non si verifica un deadlock. –

Problemi correlati