¿Cómo limpio SqlDependency de la memoria de SQL Server?

Resuelto JeremyK asked hace 13 años • 1 respuestas

¿Cómo limpio SQL Server para deshacerme de SqlDependencylos objetos caducados? Después de recibir el evento del SqlDepedencyobjeto, necesito crear uno nuevo antes de poder obtener un evento nuevo. Sin embargo, el uso de memoria del proceso de SQL Server aumenta hasta que se agota la memoria permitida (SQL Server Express). ¿Cómo me deshago de consultas antiguas?

Código:

// Func: RegisterTableListener
using (SqlConnection cn = new SqlConnection(Properties.Settings.Default.DatabseEventConnectionString))
{
if (cmd == null)
{
    cmd = cn.CreateCommand();

    cmd.CommandType = CommandType.Text;
    cmd.CommandText = "SELECT HostName, LastStatus, LastDetails, xml FROM dbo.[SystemTable]";
}

lock (cmd)
{
    cmd.Connection = cn;
    cn.Open();
    cmd.Notification = null;

    //  creates a new dependency for the SqlCommand
    if (dep == null)
        dep = new SqlDependency(cmd);
    //  creates an event handler for the notification of data
    //      changes in the database.
    dep.OnChange += new OnChangeEventHandler(dependency_OnChange);


    using (SqlDataReader reader = cmd.ExecuteReader())
    {
    // code here to read
    }
}
}

// Func dependency_OnChange
//SqlDependency dep = sender as SqlDependency;
dep.OnChange -= dependency_OnChange;
RegisterTableListener();
JeremyK avatar Dec 15 '11 04:12 JeremyK
Aceptado

Existe un comportamiento específico de la clase Microsoft SqlDependency. Aunque llame al método SqlDependency.Stop(), libere SqlCommand y SqlConnection; aún mantiene grupos de conversación (sys.conversation_groups) y puntos finales de conversación (sys.conversation_endpoints) en la base de datos. Parece que SQL Server carga todos los puntos finales de la conversación y usa toda la memoria permitida. Aquí pruebas que lo demuestran. Entonces, para limpiar todos los puntos finales de conversación no utilizados y liberar toda la memoria ocupada, debe iniciar este código SQL para su base de datos:

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;

Además, SqlDependency no le brinda la oportunidad de recibir TODOS los cambios de la tabla. Por lo tanto, no recibe notificaciones sobre los cambios durante la resuscripción de SqlDependency.

Para evitar todos estos problemas, utilicé otra realización de código abierto de la clase SqlDependency: SqlDependencyEx . Utiliza un disparador de base de datos y una notificación nativa de Service Broker para recibir eventos sobre cambios en la tabla. Este es un ejemplo 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 esto ayude.

dyatchenko avatar Jan 26 '2015 10:01 dyatchenko