Wprowadzenie
Dzieje się tak często, gdy inicjator zapomina o transakcji MS SQL Server. Najlepszym przykładem może być następujący:w SSMS wykonywany jest skrypt, który poprzez instrukcję „begin tran” rozpoczyna transakcję i pojawia się błąd; jednak „commit” lub „rollback” nie przechodzą, a inicjator wykonania opuścił to zapytanie na długi czas. W rezultacie pojawia się coraz większa fluktuacja, jeśli chodzi o blokowanie zapytań żądających dostępu do zamkniętych zasobów (tabele i zasoby serwera, takie jak pamięć RAM, procesor i system wejścia-wyjścia).
W tym artykule przyjrzymy się jednemu ze sposobów na zautomatyzowanie procesu usuwania zapomnianych transakcji.
Rozwiązanie
Zdefiniujmy zapomnianą transakcję jako aktywną (obecnie wykonaną) transakcję, która przez wystarczająco długi okres czasu T nie ma aktywnych (aktualnie wykonywanych) zapytań.
Oto ogólny algorytm usuwania takich transakcji:
- Tworzenie tabeli do przechowywania i analizowania informacji o aktualnie zapomnianych transakcjach, a także tabeli do sortowania i archiwizowania transakcji wybranych z pierwszej tabeli poprzez akcje usuwania.
- Zbieranie informacji (transakcje i ich sesje bez zapytań, tj. transakcje, które zostały wykonane i zapomniane w określonym czasie T.
- Odświeżenie tabeli zawierającej wszystkie aktualnie zapomniane transakcje, które otrzymaliśmy w kroku 1 (jeśli zapomniana transakcja uzyskała aktywne zapytanie, taka transakcja zostanie usunięta z tej tabeli).
- Pobieranie sesji, które musimy zabić (sesja ma co najmniej jedną transakcję, która została umieszczona jako zapomniana w tabeli z kroku 1 K lub więcej razy, a sesja miała brakujące aktywne zapytanie tyle samo razy).
- Archiwizowanie danych, które zamierzamy usunąć (szczegóły dotyczące sesji, połączeń i transakcji, które zostaną zabite).
- Usuwam wybrane sesje.
- Usunięcie przetworzonych wpisów wraz z tymi, których nie można usunąć i które zbyt długo znajdowały się w tabeli od kroku 1.
Zobaczmy teraz, jak możemy zaimplementować ten algorytm.
Przede wszystkim musimy utworzyć tabelę do przechowywania i analizowania informacji o wszystkich obecnie zapomnianych transakcjach:
USE [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[SessionTran]( [SessionID] [int] NOT NULL, [TransactionID] [bigint] NOT NULL, [CountTranNotRequest] [tinyint] NOT NULL, [CountesS ] [tinyint] NOT NULL, [TransactionBeginTime] [datetime] NOT NULL, [InsertUTCDate] [datetime] NOT NULL, [UpdateUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_SessionTran] KLUCZ PODSTAWOWY ([SessionID] ASC, [TransactionID] ASC) Z (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY]TABELA BRAMKARÓW [srv].[SessionTran] ADDCountes DESTRAINT (DF_S) ADDCountes DESTRAINT (DF_S) 0)) DLA [CountTranNotRequest]TABELI BRAMKARÓW [srv].[SessionTran] DODAJ OGRANICZENIE [DF_SessionTran_CountSessionNotRequest] DOMYŚLNE ((0)) DLA [CountSessionNotRequest]TABELI BRAMKARÓW [srv].[SessionTran] DODAJ OGRANICZENIE [DF_InsertUTGETRANGET] ) FOR [InsertUTCDate]TABELA BRAMKARZA [srv].[Sesja Tran] DODAJ OGRANICZENIE [DF_SessionTran_UpdateUTCDate] DOMYŚLNE (getutcdate()) DLA [UpdateUTCDate] GO
Tutaj:
1) SessionID — identyfikator sesji
2) TransactionID — zapomniany identyfikator transakcji
3) CountTranNotRequest — ile razy transakcja została zarejestrowana jako zapomniana
4) CountSessionNotRequest — ilość razy sesja bez aktywnych zapytań została zarejestrowana i miała zapomnianą transakcję
5) TransactionBeginTime — data i godzina zainicjowania zapomnianej transakcji
6) InsertUTCDate — data i godzina utworzenia wpisu (UTC)
7) UpdateUTCDate — data i godzina aktualizacji wpisu (UTC)
Następnie utworzymy tabelę do archiwizacji i sortowania transakcji z pierwszej tabeli według działań usuwania:
[rozwiń tytuł =”Kod „]
USE [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[KillSession]( [ID] [int] IDENTITY(1,1) NOT NULL, [session_id] [smallint] NOT NULL, [transaction_id] [bigint ] NOT NULL, [login_time] [datetime] NOT NULL, [nazwa_hosta] [nvarchar](128) NULL, [nazwa_programu] [nvarchar](128) NULL, [identyfikator_procesu_hosta] [int] NULL, [wersja_klienta] [int] NULL , [nazwa_interfejsu_klienta] [nvarchar](32) NULL, [identyfikator_zabezpieczeń] [varbinary](85) NOT NULL, [nazwa_logowania] [nvarchar](128) NOT NULL, [nt_domain] [nvarchar](128) NULL, [nt_user_name] [nvarchar](128) NULL, [status] [nvarchar](30) NOT NULL, [context_info] [varbinary](128) NULL, [cpu_time] [int] NOT NULL, [memory_usage] [int] NOT NULL, [ total_scheduled_time] [int] NOT NULL, [total_elapsed_time] [int] NOT NULL, [endpoint_id] [int] NOT NULL, [last_request_start_time] [datetime] NOT NULL, [last_request_end_time] [datetime] NULL, [odczyty] [bigint] NOT NULL, [zapisuje] [bigint] NIE NULL, [odczyty_logiczne] [bigint] NIE NULL, [jest_procesem_użytkownika] [bit] NIE NULL, [rozmiar_tekstu] [int] NIE NULL, [język] [nvarchar](128) NULL, [format_daty] [nvarchar](3) NULL, [pierwsza_data] [mały] NIE NULL, [identyfikator_cytatu] [bit] NIE NULL, [arithabort] [bit] NOT NULL, [ansi_null_dflt_on] [bit] NOT NULL, [ansi_defaults] [bit] NOT NULL, [ansi_warnings] [bit] NOT NULL, [ansi_padding] [bit] NOT NULL, [ansi_nulls] [bit] NOT NULL, [concat_null_yields_null] [bit] NOT NULL, [transaction_isolation_level] [smallint] NOT NULL, [lock_timeout] [int] NOT NULL, [deadlock_priority] [int] NOT NULL, [row_count] [bigint] NOT NULL , [prev_error] [int] NOT NULL, [original_security_id] [varbinary](85) NOT NULL, [original_login_name] [nvarchar](128) NOT NULL, [last_successful_logon] [datetime] NULL, [last_unsuccessfultime_logon] [ [unsuccessful_logons] [bigint] NULL, [group_id] [int] NOT NULL, [database_id] [smallint] NOT NULL, [authenticating_database_id] [int] NULL, [open_transaction_count] [int] NOT NULL, [most_recent_session_id] [int] NULL , [czas_połączenia] [ datetime] NULL, [net_transport] [nvarchar](40) NULL, [protocol_type] [nvarchar](40) NULL, [protocol_version] [int] NULL, [encrypt_option] [nvarchar](40) NULL, [auth_scheme] [nvarchar ](40) NULL, [powinowactwo_węzła] [małe] NULL, [liczba_odczytów] [int] NULL, [num_writes] [int] NULL, [ostatnie_odczyt] [dataczas] NULL, [ostatni_zapis] [datagodzina] NULL, [rozmiar_netto_pakietu] [ int] NULL, [client_net_address] [nvarchar](48) NULL, [client_tcp_port] [int] NULL, [local_net_address] [nvarchar](48) NULL, [local_tcp_port] [int] NULL, [connection_id] [unikalny identyfikator] NULL, [parent_connection_id] [uniqueidentifier] NULL, [most_recent_sql_handle] [varbinary](64) NULL, [LastTSQL] [nvarchar](max) NULL, [transaction_begin_time] [datetime] NOT NULL, [CountTranNotRequest] [tinyint] NOT NULL, [CountSeses ] [tinyint] NOT NULL, [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_KillSession] KLUCZ PODSTAWOWY SKLASTROWANY ([ID] ASC) Z (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]GOALTER TABLE [srv].[KillSession] DODAJ OGRANICZENIE [DF_KillSession_InsertUTCDate] DOMYŚLNE (getutcdate()) DLA [InsertUTCDate]GO[/rozwiń]
Tutaj wszystkie pola są pobierane z reprezentacji systemowych „sys.dm_exec_sessions” i „sys.dm_exec_connections”, a „InsertUTCDate” określa czas UTC utworzenia wpisu.
Następnie, aby wykonać pozostałe kroki, zaimplementujmy procedurę składowaną [srv].[AutoKillSessionTranBegin] w następujący sposób:
[rozwiń tytuł =”Kod „]
UŻYJ [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER PROCEDURA ONGOCREATE [srv].[AutoKillSessionTranBegin] @minuteOld int, --wiek wykonanej transakcji (T min.) @countIsNotRequests int --ilość razy, gdy została umieszczona w tabela (K)ASBEGIN SET NOCOUNT ON; USTAW POZIOM IZOLACJI TRANSAKCJI CZYTAJ NIEZAANGAŻOWANY; zadeklaruj tabelę @tbl ( SessionID int, TransactionID bigint, IsSessionNotRequest bit, TransactionBeginTime datetime ); --pobieranie informacji (transakcje i ich sesje, które nie mają żądań, tj. transakcje, które zostały zainicjowane i zapomniane) wstaw do @tbl ( SessionID, TransactionID, IsSessionNotRequest, TransactionBeginTime ) wybierz t.[session_id] jako SessionID , t.[transaction_id] jako TransactionID , przypadek, gdy istnieje (wybierz top(1) 1 z sys.dm_exec_requests jako r, gdzie r.[session_id]=t.[session_id]), a następnie 0 w przeciwnym razie 1 zakończ jako IsSessionNotRequest , (wybierz top(1) ta.[transaction_begin_time ] z sys.dm_tran_active_transactions jako ta gdzie ta.[transaction_id]=t.[transaction_id]) jako TransactionBeginTime z sys.dm_tran_session_transactions jako t gdzie t.[is_user_transaction]=1 i nie istnieje (wybierz top(1) 1 z sys.dm_exec_requests jako r, gdzie r.[id_transakcji]=t.[id_transakcji]); --odświeżanie tabeli zawierającej wszystkie zainicjowane transakcje bez żądań;scal srv.SessionTran jako st używając @tbl as t na st.[SessionID]=t.[Identyfikator Sesji] i st.[Identyfikator Transakcji]=t.[Identyfikator Transakcji] po dopasowaniu then update set [UpdateUTCDate] =getUTCDate() , [CountTranNotRequest] =st.[CountTranNotRequest]+1 , [CountSessionNotRequest] =przypadek, gdy (t.[IsSessionNotRequest]=1) then (st.[CountSessionNotRequest]+1) else 0 end , [TransactionBeginTime] =t.[TransactionBeginTime] jeśli nie pasuje do celu, a następnie wstaw wartości ( [SessionID] ,[TransactionID] ,[TransactionBeginTime] ) ( t.[SessionID] ,t.[TransactionID] ,t.[TransactionBeginTime] ) jeśli nie pasuje do źródła, usuń; --lista sesji, które należy usunąć (te, które zawierają zapomniane transakcje) zadeklaruj tabelę @kills ( SessionID int ); --детальная informacje o arхива zadeklaruj @kills_copy table ( SessionID int, TransactionID bigint, CountTranNotRequest tinyint, CountSessionNotRequest tinyint, TransactionBeginTime datetime ) --zbieranie sesji, które musimy zabić --która sesja została oznaczona jako nie posiadająca co najmniej jednej transakcji żądania @countIsNotRequests razy --a ta sesja została oznaczona jako nie posiadająca aktywnych żądań tyle samo razy wstaw do @kills_copy ( SessionID, TransactionID, CountTranNotRequest, CountSessionNotRequest, TransactionBeginTime ) select SessionID, TransactionID, CountTranNotRequest, CountSessionNotRequest, TransactionBegin.Session from s gdzie [CountTranNotRequest]>[email protected] i [CountSessionNotRequest]>[email protected] i [TransactionBeginTime]<=DateAdd(minuta,[email protected],GetDate()); --archiwizowanie danych, które musimy usunąć (szczegóły dotyczące sesji do usunięcia, połączeń i transakcji) INSERT INTO [srv].[KillSession] ([identyfikator_sesji] ,[id_transakcji] ,[czas_logowania] ,[nazwa_hosta] ,[nazwa_programu ] ,[identyfikator_procesu_hosta] ,[wersja_klienta] ,[nazwa_interfejsu_klienta] ,[identyfikator_zabezpieczeń] ,[nazwa_logowania] ,[domena_nt] ,[nazwa_użytkownika_nt] ,[status] ,[informacje_kontekstowe] ,[czas_cpu] ,[czas_użytkowania_pamięci] ,[ched" [całkowity_czas_upływu] ,[id_punktu_końcowego] ,[czas_rozpoczęcia_ostatniego_żądania] ,[czas_zakończenia_ostatniego_żądania] ,[odczyty] ,[zapis] ,[odczyty_logiczne] ,[jest_procesem_użytkownika] ,[rozmiar_tekstu] ,[język] ,[identyfikator,[pierwszy_format_daty] , ] ,[arithabort] ,[ansi_null_dflt_on] ,[ansi_defaults] ,[ansi_warnings] ,[ansi_padding] ,[ansi_nulls] ,[concat_null_yields_null] ,[transaction_isolation level] ,[lock_timeout] ,[deadlock_priority] ,[row_original_log] ,[nazwa_wstępnej_instrukcji_zabezpieczeń] ,[prev last_successful_logon] ,[last_unsuccessful_logon] ,[unsuccessful_logons] ,[group_id] ,[database_id] ,[authenticating_database_id] ,[open_transaction_count] ,[most_recent_session,[comconnect_type] [identyfikator_profilu]] , ,[schemat_autoryzacji] ,[powinowactwo_węzła] ,[liczba_odczytań] ,[liczba_zapisów] ,[ostatni_odczyt] ,[ostatni_zapis] ,[rozmiar_pakietu_netowego] ,[adres_sieci_klienta] ,[port_tcp_klienta] ,[local_n et_address] ,[local_tcp_port] ,[connection_id] ,[parent_connection_id] ,[most_recent_sql_handle] ,[LastTSQL] ,[transaction_begin_time] ,[CountTranNotRequest] ,[CountSessionNotRequest]). [czas_logowania] ,ES.[nazwa_hosta] ,ES.[nazwa_programu] ,ES.[id_procesu_hosta] ,ES.[wersja_klienta] ,ES.[nazwa_interfejsu_klienta] ,ES.[identyfikator_zabezpieczeń] ,ES.[nazwa_logowania] ,ES.[domena_nt_ ] ,ES.[nazwa_użytkownika_nt] ,ES.[stan] ,ES.[informacje_kontekstowe] ,ES.[czas_cpu] ,ES.[wykorzystanie_pamięci] ,ES.[całkowity_zaplanowany_czas] ,ES.[całkowity_czas_upływający] ,ES.[id_punktu_końcowego] , ES.[czas_rozpoczęcia_ostatniego_żądania] ,ES.[czas_zakończenia_ostatniego_żądania] ,ES.[odczyty] ,ES.[zapis] ,ES.[odczyty_logiczne] ,ES.[jest_proces_użytkownika ] ,ES.[rozmiar_tekstu] ,ES.[język] ,ES.[format_daty] ,ES.[pierwsza_data] ,ES.[identyfikator_cytatu] ,ES.[arithabort] ,ES.[ansi_null_dflt_on] ,ES.[ansi_defaults] , ES.[ansi_warnings] ,ES.[ansi_padding] ,ES.[ansi_nulls] ,ES.[concat_null_yields_null] ,ES.[poziom_izolacji_transakcji] ,ES.[czas_blokady] ,ES.[priorytet_zakleszczenia] ,ES.[liczba_wierszy] [poprzedni_błąd] ,ES.[pierwotny_identyfikator_zabezpieczeń] ,ES.[oryginalna_nazwa_logowania] ,ES.[ostatni_pomyślny_logon] ,ES.[ostatni_nieudany_logon] ,ES.[niepowodzenie_logowania_] ,ES.[identyfikator_grupy_danych_ES. ] ,ES.[liczba_otwartych_transakcji] ,WE.[najnowsze_id_sesji] ,WE.[czas_połączenia] ,WE.[net_transport] ,WE.[typ_protokołu] ,WE.[wersja_protokołu ] ,EC.[opcja_szyfrowania] ,EC.[schemat_autoryzacji] ,EC.[powinowactwo_węzła] ,EC.[liczba_odczytów] ,EC.[liczba_zapisów] ,EC.[ostatni_odczyt] ,EC.[ostatni_zapis] ,EC.[net_packet_size] , EC.[client_net_address] ,EC.[client_tcp_port] ,EC.[local_net_address] ,EC.[local_tcp_port] ,EC.[connection_id] ,EC.[parent_connection_id] ,EC.[most_recent_sql_handle] ,(wybierz na górę(1) system .[SessionID]=ES.[session_id] sprzężenie wewnętrzne sys.dm_exec_connections EC with(readuncommitted) na EC.session_id =ES.session_id; --gathering session wstaw do @kills ( SessionID ) wybierz [SessionID] z @kills_copy group przez [SessionID]; zadeklaruj @SessionID int; --usuwanie sesji while(exists(select top(1) 1 from @kills)) begin select top(1) @SessionID=[SessionID] from @kills; ROZPOCZNIJ WYPRÓBUJ EXEC sp_executesql N'kill @SessionID', N'@SessionID INT', @SessionID; END TRY BEGIN CATCH END CATCH usuń z @kills gdzie [Identyfikator Sesji][email protected]; end wybierz st.[Identyfikator Sesji] ,st.[Identyfikator Transakcji] do #tbl z srv.SessionTran jako st, gdzie st.[CountTranNotRequest]>=250 lub st.[CountSessionNotRequest]>=250 lub istnieje (wybierz top(1) 1 z @kills_copy kc gdzie kc.[Identyfikator Sesji]=st.[Identyfikator Sesji]); --Usuwanie przetworzonych wpisów wraz z tymi, których nie można usunąć i które zbyt długo znajdowały się w tabeli. t.[Identyfikator Transakcji]=st.[Identyfikator Transakcji]; upuść tabelę #tbl;ENDGO[/rozwiń]
Krok 7 algorytmu jest implementowany przez jeden z tych dwóch liczników – CountTranNotRequest lub CountSessionNotRequest – osiągając wartość 250.
Wynik
W tym artykule przyjrzeliśmy się implementacji procesu, który automatycznie usuwa zapomniane transakcje.
Ta metoda pozwala nam zautomatyzować proces usuwania zapomnianej transakcji. Powoduje to zmniejszenie lub zatrzymanie wzrostu wahań w blokowaniu powodowanym przez takie transakcje. Tak więc wydajność DBMS jest chroniona przed działaniami, które mogą spowodować zapomniane transakcje.
Źródła:
» sys.dm_exec_requests
» sys.dm_tran_active_transactions
» sys.dm_tran_session_transactions
» sys.dm_exec_sql_text
» sys.dm_exec_sessions
» sys.connections_ILLm