2011-12-14 9 views
9

Come si pulisce SQL Server per eliminare gli oggetti SqlDependency scaduti? Dopo aver ricevuto l'evento dall'oggetto SqlDepedency, è necessario crearne uno nuovo prima di poter ottenere un nuovo evento. Tuttavia, l'utilizzo della memoria del processo di SQL Server sale fino a quando non esaurisce la memoria consentita (SQL Server Express). Come faccio a sbarazzarmi di vecchie query?Come si pulisce SqlDependency dalla memoria di SQL Server?

Codice:

// 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

Come si creano gli oggetti 'SqlDependency'? Per favore pubblica il tuo codice. Li stai smaltendo correttamente? – Oded

+0

Ill aggiorno il mio commento con il codice quando sarò al lavoro domani. Sudo: SqlDipendenza dep = new SqlDependency (cmd); dep.OnChange + = fun; SqlDependency non implementa IDisposable – JeremyK

+0

Ho aggiornato con il codice. Anche quando eseguo solo un'istanza di SqlDepdency e chiamiamo Stop and Start ogni volta, la memoria sale. Non ho idea di cosa stia succedendo. – JeremyK

risposta

12

C'è un comportamento specifico di classe di Microsoft SqlDependency. Anche se si chiama il metodo SqlDependency.Stop(), rilascia SqlCommand e SqlConnection - mantiene ancora 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. Here test che lo dimostrano. Così, per pulire tutti gli endpoint di conversazione non utilizzate e liberare tutta la memoria occupata è necessario avviare questo codice SQL per il 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 si riceve alcuna notifica sulle modifiche durante la riscrittura 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 relativi alle 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.

+1

qual è il significato di questa riga WHERE CEP.state = 'DI' o CEP.state = 'CD'. cosa stai cercando di fare. per favore aiutami a capire. grazie – Mou

+0

@Me 'DI' significa" DisconnectedInbound "," CD "significa" Chiuso ". Gli endpoint delle conversazioni con questi marchi non hanno una durata impostata da 'SqlDependency'. Significa che saranno in un database finché non li pulirai con forza. Secondo l'articolo http://rusanu.com/2014/03/31/how-to-prevent-conversation-endpoint-leaks/ (alla fine) è un modo giusto per ripulire i vecchi endpoint di conversazione. – dyatchenko

+0

significa che se uso questo sql 'WHERE CEP.state = 'DI' o CEP.state = 'CD'' allora la vecchia conversazione verrà rimossa? – Mou

0

sto affrontando esattamente lo stesso problema. Sto creando un componente di accesso ai dati che memorizza nella cache alcune query da un database di SQL Server 2005. La cache è invalidata utilizzando questo nuovo, brillante, non troppo nuovo, approccio SqlDependency.

Poiché questo componente verrà utilizzato in ASP.NET nonché nelle applicazioni Forms e Windows Service, sto cercando un modo comune per chiamare (internamente) SqlDependency.Stop().

L'utilizzo di un finalizzatore è stata anche la mia prima idea e non ha funzionato. Il mio secondo tentativo era l'utilizzo di un gestore di eventi per AppDomain.DomainUnload.

Dopotutto, sembra funzionare ... Ma il webserver integrato in VS 2005 si bloccherà per 4-5 minuti con CPU al 100% mentre si esegue SqlDependy.Stop(). Infatti, non riesco a ricordare nessun altro processo di blocco della mia macchina (Pentium M laptop) riproducibile così male da rendere difficoltoso l'avvio del Task Manager ... Non mi aspettavo che ciò fosse possibile dallo spazio utente e persino dal codice gestito (SQL Server è in esecuzione su un'altra casella.) Durante questo periodo, anche Performance Monitor si rifiuta di registrare qualsiasi cosa, quindi non posso dire se ci sono molti handle di Windows o eccezioni .NET coinvolte o altro ...

Chiamarlo dall'evento Application_End funziona correttamente (e richiede solo pochi millisecondi), tuttavia questo è specifico per ASP.NET.

Tutte le idee

+0

Ho finito per rinunciare all'uso del broker di servizi. Non ero in grado di capire cosa causasse la perdita. – JeremyK

Problemi correlati