2011-12-14 85 views
9

如何清理SQL Server以擺脫過期的SqlDependency對象?在我收到來自SqlDepedency對象的事件後,我需要創建一個新對象,然後才能獲得新事件。但是,SQL Server進程的內存使用量會一直攀升,直到耗盡允許的內存(SQL Server Express)。我如何擺脫舊的查詢?如何從SQL Server內存中清理SqlDependency?

代碼:

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

你是如何創建`SqlDependency`對象的?請發佈您的代碼。你正確地處理它們嗎? – Oded 2011-12-14 21:27:22

+0

我明天上班時,用代碼更新我的評論。 Sudo: SqlDependency dep = new SqlDependency(cmd); dep。OnChange + =樂趣; SqlDependency不執行IDisposable – JeremyK 2011-12-15 00:19:54

+0

我已更新代碼。即使我只運行一個SqlDepdency實例並每次調用Stop和Start時,內存都會攀升。至於發生了什麼,我無能爲力。 – JeremyK 2011-12-15 14:35:46

回答

12

存在Microsoft SqlDependency類的特定行爲。即使您調用SqlDependency.Stop()方法,但釋放SqlCommand和SqlConnection - 它仍然保留數據庫中的對話組(sys.conversation_groups)和對話端點(sys.conversation_endpoints)。它看起來像SQL Server加載每個對話端點並使用所有允許的內存。 Here測試證明它。因此,清理所有未使用的會話端點和釋放你要開始這個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

我面對完全一樣的問題。我正在創建一個緩存來自SQL Server 2005數據庫的一些查詢的數據訪問組件。 SqlDependency方法使用這個閃亮的新的,不再那麼新的緩存失效。因爲這個組件將在ASP.NET以及Forms和Windows服務應用程序中使用,所以我正在尋找一種通用的方法來(在內部)調用SqlDependency.Stop()。

使用終結器也是我的第一個想法,但這並沒有解決。我第二次嘗試使用AppDomain.DomainUnload的事件處理程序。

畢竟,這似乎工作...但在執行SqlDependy.Stop()時,VS 2005中的內置Web服務器將掛起4-5分鐘100%的CPU。事實上,我不記得任何其他進程阻塞我的機器(Pentium M筆記本電腦)可重現如此糟糕,我幾乎不能提出任務管理器...我沒想到這是可能的用戶空間,甚至託管代碼(SQL Server正在另一個盒子上運行)。在此期間,即使性能監視器拒絕記錄任何內容,所以我不能說是否有很多Windows句柄或.NET異常包含在內或者其他任何內容...

從Application_End事件調用它可以正常工作(並且只需要幾毫秒),但是這僅限於ASP.NET。

任何想法