Как очистить SqlDependency из памяти SQL Server? - PullRequest
12 голосов
/ 15 декабря 2011

Как мне очистить SQL Server, чтобы избавиться от устаревших SqlDependency объектов?После того, как я получил событие от объекта SqlDepedency, мне нужно создать новое, прежде чем я смогу получить новое событие.Однако использование памяти процессом SQL Server увеличивается, пока не исчерпается разрешенная память (SQL Server Express).Как мне избавиться от старых запросов?

Код:

// 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();

Ответы [ 2 ]

16 голосов
/ 26 января 2015

Существует определенное поведение класса Microsoft SqlDependency. Несмотря на то, что вы вызываете метод SqlDependency.Stop (), освобождаете SqlCommand и SqlConnection - он по-прежнему сохраняет группы беседы (sys.conversation_groups) и конечные точки беседы (sys.conversation_endpoints) в базе данных. Похоже, что SQL Server загружает каждую конечную точку диалога и использует всю разрешенную память. Здесь тесты, которые доказывают это. Итак, чтобы очистить все неиспользуемые конечные точки диалога и освободить всю занятую память, вам нужно запустить этот код SQL для вашей базы данных:

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;

Кроме того, SqlDependency не дает вам возможности получать ВСЕ изменения таблицы. Таким образом, вы не получите уведомление об изменениях во время повторной подписки SqlDependency.

Чтобы избежать всех этих проблем, я использовал другую реализацию класса SqlDependency с открытым исходным кодом - SqlDependencyEx . Он использует триггер базы данных и собственное уведомление Service Broker для получения событий об изменениях таблицы. Это пример использования:

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);

Надеюсь, это поможет.

0 голосов
/ 20 декабря 2011

У меня точно такая же проблема. Я создаю компонент доступа к данным, который кэширует некоторые запросы из базы данных SQL Server 2005. Кэш аннулирован с использованием этого блестящего нового, а не ооочень нового, подхода SqlDependency.

Поскольку этот компонент будет использоваться в ASP.NET, а также в приложениях Forms и Windows Service, я ищу общий способ (внутренне) вызова SqlDependency.Stop ().

Использование финализатора было моей первой идеей, и это не сработало. Второй попыткой было использование обработчика событий для AppDomain.DomainUnload.

В конце концов, это похоже на работу ... Но встроенный веб-сервер в VS 2005 будет зависать в течение 4-5 минут со 100% процессором при выполнении SqlDependy.Stop (). На самом деле, я не могу вспомнить ни одного другого процесса, блокирующего мою машину (ноутбук Pentium M), воспроизводимого настолько плохо, что я едва мог запустить диспетчер задач ... Я не ожидал, что это возможно из пользовательского пространства и даже из управляемого кода (SQL Server работает на другом компьютере.) В течение этого времени даже системный монитор отказывается что-либо регистрировать, поэтому я не могу сказать, существует ли множество дескрипторов Windows или исключений .NET или что-то еще ...

Вызов его из события Application_End работает нормально (и занимает всего несколько миллисекунд), однако это характерно для ASP.NET.

Любые идеи

...