Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como faço para limpar SqlDependency da memória do SQL Server?


Há um comportamento específico da classe Microsoft SqlDependency. Mesmo que você chame o método SqlDependency.Stop(), libere SqlCommand e SqlConnection - ele ainda mantém grupos de conversação (sys.conversation_groups) e terminais de conversação (sys.conversation_endpoints) no banco de dados. Parece que o SQL Server carrega todos os endpoints de conversa e usa toda a memória permitida. Aqui testes que comprovam isso. Portanto, para limpar todos os endpoints de conversação não utilizados e liberar toda a memória ocupada, você deve iniciar este código SQL para seu banco de dados:
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;

Além disso, SqlDependency não lhe dá a oportunidade de receber TODAS as alterações da tabela. Portanto, você não recebe notificação sobre alterações durante a nova assinatura do SqlDependency.

Para evitar todos esses problemas, usei outra realização de código aberto da classe SqlDependency - SqlDependencyEx . Ele usa o gatilho do banco de dados e a notificação nativa do Service Broker para receber eventos sobre as alterações da tabela. Este é um exemplo de uso:
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);

Espero que isto ajude.