Mamy problem z niektórymi kodami bazy danych, które najwyraźniej są wykonywane z niewłaściwym poziomem izolacji. W tej części kodu należy wykonać polecenie "READ UNCOMMITTED", aby zminimalizować blokady. Niespójne dane są w tym momencie prawidłowe."USTAWIENIE POZIOMU IZOLACJI PRZESYŁANIA CZYTA NIEKOMMITOWANE" nie jest używane? Czy patrzę w niewłaściwy sposób?
Jednak kod faktycznie czyta się z READ COMMITTED, a my nie możemy zrozumieć dlaczego.
Oto co zrobiliśmy:
- Otwórz połączenie
- wykonać na tym związku "SET TRANSAKCJI IZOLACJA LEVEL READ UNCOMMITTED"
- Hit punkt przerwania
- Execute SQL
W punkcie przerwania wydajemy to polecenie do bazy danych:
select s.session_id, s.transaction_isolation_level, st.text from sys.dm_exec_sessions s
inner join sys.sysprocesses sp on (sp.spid = s.session_id)
CROSS APPLY sys.dm_exec_sql_text(sp.sql_handle) st
Ten SQL raporty zbiorcze 4 połączenia w tej chwili, z których jeden jest nasz związek, że możemy krok poza przerwania wykonać naszą SQL z, który ma ten stan:
53 2 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
tj. sesja 53 ma poziom izolacji 2 (READ COMMITTED), a ostatnim SQL, który został wykonany w tej sesji, było polecenie "SET TRANSACTION ...".
Jak to możliwe?
W programie SQL Profiler zweryfikowaliśmy, że to połączenie nie było aktywne, zanim nasz kod .NET go otworzył, więc nie został użyty ponownie z puli połączeń.
Jednak z nowym połączeniem i jedynym wykonanym na nim SQL, który wyraźnie powiedział, że powinien używać polecenia READ UNCOMMITTED, w jaki sposób połączenie może nadal być READ COMMITTED?
Na co powinniśmy tutaj patrzeć?
Łańcuch łączący (bitami redacted) jest tak:
SERVER=hostname;DATABASE=dbname;Integrated Security=false;USER ID=sa;PASSWORD=****;Application Name=appname;Type System Version=SQL Server 2000;Workstation ID=hostname;
połączenia są normalne SqlConnection
połączenia otwarte w normalny sposób.
Niestety nie jesteśmy w stanie odtworzyć problemu, jeśli piszemy normalny kod otwierający SqlConnection, więc musi być coś ze stanem aplikacji, ale ponieważ SqlProfiler i Sql Server mówią nam, że tak, SQL został wykonany, ale nie, nie obchodzi mnie to.
Co może wpłynąć na to?
Ten sam kod otwiera również inne połączenia, to jest kod jest wykonywany wiele razy i otwiera wiele połączeń, więc więcej niż jedno połączenie kończy się w puli, ale tylko pierwsze połączenie kończy się mając ten problem.
To jest SQL Server 2008 R2 i odtworzyliśmy ten problem również w 2012 roku.
Edit
OK, niektóre więcej informacji.
pierwsze, umożliwiają łączenie, a raczej nie jesteśmy wyraźnie wyłączając go, ani nie jesteśmy kręci ciąg połączenia, aby baseny „n”.
Jednak ta gra jest pierwszą otwierane z tego konkretnego ciągu połączenia, zatem nie jest pobierana z puli. Zobacz także moją notatkę poniżej o tym, że jest trwale "chora".
To połączenie jest tworzone tak:
var conn = new SqlConnection(...);
conn.StateChance += connection_StateChange;
private void connection_StateChange(Object sender, StateChangeEventArgs e)
{
if (e.CurrentState == ConnectionState.Open)
{
using (IDbCommand cmd = ((SqlConnection)sender).CreateCommand())
{
cmd.CommandText = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED";
cmd.ExecuteNonQuery();
}
My nie wykonując żadnej innej SQL wcześniej.
Należy pamiętać, że ten kod jest używany wiele razy razy w czasie trwania aplikacji, jest to tylko pierwsze połączenie, które otwiera, które kończy się źle.
To połączenie również staje się trwale chora. Ponieważ za każdym razem, gdy otwieramy połączenie (nawet jeśli możemy je wydostać z puli połączeń), wykonuje się powyższe zdarzenie zmiany stanu, próbując ponownie ustawić poziom izolacji. To również się nie udaje, ale tylko dla tego pojedynczego połączenia.
Dodatkowo znaleźliśmy jedną rzecz, która ma na to wpływ, ponieważ opublikowałem to pytanie.
Zmieniając ciąg połączenia, które napisałem powyżej:
...;Type System Version=SQL Server 2000;...
do tego:
...;Type System Version=SQL Server 2008;MultipleActiveResultSets=true;...
to ten problem zniknie, przy zerwaniu wymienionych wcześniej, połączenie tej pory „READ NIEZGODNY "stan.
To był czerwony śledzia, połączenie nie było już zgłaszane w naszym przeglądzie, dopóki faktycznie nie wykonaliśmy kodu tam.
Kontynuujemy nasze debugowanie.
Skopiowałem powyższy kod i otworzyłem połączenie, a otrzymałem oczekiwany wynik odczytu niezatwierdzonego połączenia. Musi istnieć inny kod ustawiający twój poziom izolacji –
Czy coś mogło ustawić 'NOEXEC' na' ON' w tym połączeniu? Jeśli zrobię to w jednej partii, a następnie uruchomię 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED' w następnej partii w jednym oknie zapytania, otrzymam dane wyjściowe, które pokazałeś - ostatnio wykonane polecenie to' SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED' kolumna 'transaction_isolation_level' nadal pokazuje, że jest ustawiona na 2. –
Zobacz moją własną odpowiedź tutaj, nie mam pewności, że odkryłem wszystkie niezbędne elementy mojego kodu w moim pytaniu, więc mam dwa umysły na temat zachowania go tutaj, Nie wydaje mi się, żeby to było dobre pytanie. –