2011-12-14 6 views
9

Jak wyczyścić serwer SQL, aby pozbyć się wygasłych obiektów SqlDependency? Po otrzymaniu zdarzenia od obiektu SqlDepedency muszę utworzyć nowy przed uzyskaniem nowego zdarzenia. Jednak użycie pamięci procesu SQL Server wspina się, dopóki nie zabraknie dozwolonej pamięci (SQL Server Express). Jak pozbyć się starych zapytań?Jak wyczyścić SqlDependency z pamięci programu SQL Server?

Kod:

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

Jak tworzysz obiekty 'SqlDependency'? Proszę zaksięguj swój kod. Czy je prawidłowo pozbywasz? – Oded

+0

Zły zaktualizuję mój komentarz kodem, kiedy jutro przyjadę do pracy. Sudo: SqlDependency dep = new SqlDependency (cmd); dep.OnChange + = zabawa; SqlDependency nie implementuje IDisposable – JeremyK

+0

Zaktualizowałem za pomocą kodu. Nawet gdy uruchamiam tylko jedną instancję SqlDepdency i wywołuję za każdym razem Stop i Start, pamięć wspina się. Nie mam pojęcia, co się dzieje. – JeremyK

Odpowiedz

12

Jest specyficzne zachowanie klasy Microsoft SqlDependency. Mimo, że wywoływana jest metoda SqlDependency.Stop(), zwalniaj SqlCommand i SqlConnection - nadal zachowuje grupy konwersacji (sys.conversation_groups) i punkty końcowe konwersacji (sys.conversation_endpoints) w bazie danych. Wygląda na to, że SQL Server ładuje każdy punkt końcowy konwersacji i używa całej dozwolonej pamięci. Here testy, które to potwierdzają. Tak, aby oczyścić wszystkie niewykorzystane punkty końcowe rozmowy i uwolnienia wszystkich okupowanych pamięć trzeba zacząć ten kod SQL do bazy danych:

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; 

Również SqlDependency nie daje możliwość otrzymania wszystkich zmian stołu ty. Tak więc nie otrzymujesz powiadomień o zmianach podczas resubscription SqlDependency.

Aby uniknąć wszystkich tych problemów, użyłem kolejnej implementacji open source klasy SqlDependency - SqlDependencyEx. Korzysta z wyzwalacza bazy danych i natywnego powiadomienia Service Broker, aby otrzymywać zdarzenia dotyczące zmian w tabeli. To jest przykład użycia:

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

Mam nadzieję, że to pomoże.

+1

jakie jest znaczenie tego wiersza GDZIE CEP.state = 'DI' lub CEP.state = 'CD'. co próbujesz zrobić. pomóż mi zrozumieć. dzięki – Mou

+0

@Mou 'DI' oznacza" DisconnectedInbound "," CD "oznacza" Zamknięty ". Konwersacje punktów końcowych z tymi znacznikami nie mają ustawionego czasu życia przez "SqlDependency". Oznacza to, że znajdą się w bazie danych, dopóki ich nie oczyścisz. Zgodnie z artykułem http://rusanu.com/2014/03/31/how-to-prevent-conversation-endpoint-leaks/ (w końcu) jest to właściwy sposób na oczyszczenie starych punktów końcowych konwersacji. – dyatchenko

+0

czy to znaczy, czy używam tego sql 'WHERE CEP.state = 'DI' lub CEP.state = 'CD'', a następnie stara konwersacja zostanie usunięta? – Mou

0

Jestem stoi dokładnie ten sam problem. Tworzę składnik dostępu do danych, który buforuje niektóre zapytania z bazy danych SQL Server 2005. Pamięć podręczna jest unieważniana za pomocą tego nowego, lśniącego, no sooo nowego podejścia SqlDependency.

Ponieważ składnik ten będzie używany w ASP.NET, a także w aplikacjach formularzy i usług systemu Windows, szukam wspólnego sposobu (wewnętrznego) wywoływania SqlDependency.Stop().

Używanie finalizatora to także mój pierwszy pomysł, a to się nie udało. Moja druga próba polegała na użyciu procedury obsługi zdarzeń dla AppDomain.DomainUnload.

Wydaje się, że to działa ... Ale wbudowany serwer WWW w VS 2005 zawiesza się na 4-5 minut z 100% procesorem podczas wykonywania SqlDependy.Stop(). Tak naprawdę nie pamiętam żadnego innego procesu, który blokowałby moją maszynę (laptop Pentium M) tak źle, że nie mogłem wychwycić Menedżera zadań ... Nie spodziewałem się, że jest to możliwe z przestrzeni użytkownika, a nawet kodu zarządzanego (Serwer SQL działa na innym polu). W tym czasie nawet Monitor wydajności odmawia rejestrowania czegokolwiek, więc nie mogę powiedzieć, czy istnieje wiele uchwytów systemu Windows lub wyjątków NET envolved czy cokolwiek innego ...

Wywołanie go z zdarzenia Application_End działa dobrze (i zajmuje tylko kilka milisekund), jednak jest to specyficzne dla środowiska ASP.NET.

Wszelkie pomysły

+0

Skończyło się na rezygnacji z używania brokera usług. Nie byłem w stanie dowiedzieć się, co spowodowało wyciek. – JeremyK

Powiązane problemy