Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Come posso pulire SqlDependency dalla memoria di SQL Server?

Esiste un comportamento specifico della classe Microsoft SqlDependency. Anche se chiami il metodo SqlDependency.Stop(), rilascia SqlCommand e SqlConnection, mantiene comunque i gruppi di conversazione (sys.conversation_groups) e gli endpoint di conversazione (sys.conversation_endpoints) nel database. Sembra che SQL Server carichi ogni endpoint di conversazione e utilizzi tutta la memoria consentita. Qui prove che lo dimostrano. Quindi, per pulire tutti gli endpoint di conversazione inutilizzati e rilasciare tutta la memoria occupata devi avviare questo codice SQL per il tuo database:

DECLARE @ConvHandle uniqueidentifier
DECLARE Conv CURSOR FOR
SELECT CEP.conversation_handle FROM sys.conversation_endpoints CEP
WHERE CEP.state = 'DI' or CEP.state = 'CD'
OPEN Conv;
FETCH NEXT FROM Conv INTO @ConvHandle;
WHILE (@@FETCH_STATUS = 0) BEGIN
    END CONVERSATION @ConvHandle WITH CLEANUP;
    FETCH NEXT FROM Conv INTO @ConvHandle;
END
CLOSE Conv;
DEALLOCATE Conv;

Inoltre, SqlDependency non ti dà l'opportunità di ricevere TUTTE le modifiche della tabella. Pertanto, non ricevi notifiche sulle modifiche durante la nuova sottoscrizione di SqlDependency.

Per evitare tutti questi problemi ho utilizzato un'altra realizzazione open source della classe SqlDependency - SqlDependencyEx . Utilizza il trigger del database e la notifica nativa di Service Broker per ricevere eventi sulle modifiche della tabella. Questo è un esempio di utilizzo:

int changesReceived = 0;
using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
          TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME)) 
{
    sqlDependency.TableChanged += (o, e) => changesReceived++;
    sqlDependency.Start();

    // Make table changes.
    MakeTableInsertDeleteChanges(changesCount);

    // Wait a little bit to receive all changes.
    Thread.Sleep(1000);
}

Assert.AreEqual(changesCount, changesReceived);

Spero che questo aiuti.