2013-02-28 15 views
15

Stiamo risolvendo una sorta di Sync Framework tra due database di SQL Server, in server separati (entrambi SQL Server 2008 Enterprise 64 bit SP2 - 10.0.4000.0), tramite collegamento connessioni al server e abbiamo raggiunto un punto in cui siamo bloccati.SQL MIN_ACTIVE_ROWVERSION() valore non cambia per molto tempo

La logica per identificare quali sono i record "in sospeso da sincronizzare" è ovviamente basata sui valori ROWVERSION, compreso l'uso di MIN_ACTIVE_ROWVERSION() per evitare letture sporche.

Tutte le operazioni SELECT sono incapsulate in SP su ciascun lato "sorgente". Questo è un esempio schematico di una SP:

PROCEDURE LoaderRetrieve(@LastStamp bigint, @Rows int) 
    BEGIN 
    ... 
    (vars handling) 
    ... 

    SET TRANSACTION ISOLATION LEVEL SNAPSHOT 

    Select TOP (@Rows) Field1, Field2, Field3 
    FROM Table 
    WHERE [RowVersion] > @LastStampAsRowVersionDataType  
    AND [RowVersion] < @MinActiveVersion 
    Order by [RowVersion] 

    END 

L'approccio funziona bene, di solito sincronizzeremo record con il tasso atteso di 600k/ora (lavoro ogni 30 secondi, dimensione del lotto = 5K), ma ad un certo punto , il processo di sincronizzazione non trova alcun singolo record da trasferire, anche se ci sono diverse migliaia di record con un valore ROWVERSION superiore al parametro @LastStamp.

Quando si verifica il motivo, abbiamo rilevato che lo MIN_ACTIVE_ROWVERSION() ha un valore inferiore (o leggermente superiore, solo 5 o 10 incrementi) alla ricerca del . Questo, naturalmente, non dovrebbe essere un problema in quanto l'approccio MIN_ACTIVE_ROWVERSION() è stato introdotto per evitare la legge sporco e le questioni posteriori, MA:

Il problema che vediamo in alcune occasioni, nel corso si verifica lo scenario di cui sopra, è che il valore per MIN_ACTIVE_ROWVERSION() non cambia durante un lungo (molto lungo) periodo di tempo, come 30/40 minuti, a volte più di un'ora. E questo valore è di gran lunga inferiore al valore @@DBTS.

Inizialmente pensavamo che questo fosse correlato a una transazione DB non ancora impegnata. Come da definizione MSDN sulla MIN_ACTIVE_ROWVERSION() (link):

Restituisce il più basso valore di rowversion attiva nel database corrente. Un valore rowversion è attivo se è utilizzato in una transazione che non è stata ancora confermata.

Ma al momento del check sessioni (sys.sysprocesses) con open_tran > 0 durante la durata di questo problema, ma non abbiamo trovato alcuna sessione con un waittime maggiore di un paio di secondi, solo uno o due occorrenze di +/- 5 minuti waittime sessioni.

Quindi, a questo punto, stiamo facendo fatica a capire la situazione: il MIN_ACTIVE_ROWVERSION() non cambia durante un lungo periodo di tempo e in questo intervallo di tempo non vengono trovate transazioni non impegnate con lunghe attese.

Non sono un DBA e potrebbe essere il caso che ci manca qualcosa nell'immagine per analizzare questo problema, fare qualche ricerca su forum e blog non ha potuto trovare nessun altro indizio. Finora open_tran> 0 era la ragione valida, ma date le circostanze che ho esposto, è chiaro che c'è qualcos'altro e non so perché.

Qualsiasi feedback è apprezzato.

+3

+1 per una domanda così ben scritta. Piuttosto che aggiungere la soluzione alla tua domanda, aggiungila come risposta. – Kermit

+6

@luiggig: le soluzioni, anche da parte vostra, dovrebbero essere pubblicate come risposte. Sentiti libero di postare quella parte come risposta. E poi accettalo, se nessun altro ne esce con uno migliore. –

risposta

6

beh, finalmente trovo la soluzione dopo aver scavato un po 'di più.

Il problema è che stavamo cercando per le sessioni con un lungo waittime, ma il vero affare è stato quello di trovare le sessioni che hanno un batch attivo da un po '.

Se c'è una sessione in cui open_tran = 1, per ottenere esattamente da quando questa transazione è aperta (e ovviamente ancora attiva, non ancora impegnata), il campo last_batch da sys.sysprocesses deve essere controllato.

Utilizzando questa query:

select 
    batchDurationMin= DATEDIFF(second,last_batch,getutcdate())/60.0, 
    batchDurationSecs= DATEDIFF(second,last_batch,getutcdate()), 
    hostname,open_tran,* from sys.sysprocesses a 
    where spid > 50 
    and a.open_tran >0 
    order by last_batch asc 

potremmo identificare una sessione con un tran aperta essere attivi oltre 30 minuti. E con i valori dell'hostname e alcuni altri controlli all'interno dei servizi web (e anche usando dbcc inputbuffer) abbiamo trovato il processo responsabile.

Quindi, la domanda finale è in realtà "c'è effettivamente una sessione attiva con una transazione senza commit", pertanto lo MIN_ACTIVE_ROWVERSION() non cambia. Stavamo solo cercando i processi con i criteri sbagliati.

Ora che sappiamo quale processo si comporta in questo modo, il prossimo passo sarà migliorarlo.

Spero che questo risultato sia utile a qualcun altro.