Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Automatyczne usuwanie zapomnianych transakcji w MS SQL Server

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:

  1. 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.
  2. Zbieranie informacji (transakcje i ich sesje bez zapytań, tj. transakcje, które zostały wykonane i zapomniane w określonym czasie T.
  3. 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).
  4. 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).
  5. Archiwizowanie danych, które zamierzamy usunąć (szczegóły dotyczące sesji, połączeń i transakcji, które zostaną zabite).
  6. Usuwam wybrane sesje.
  7. 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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak uzyskać ostatnio wstawiony identyfikator?

  2. Eksportowanie danych w SQL Server jako INSERT INTO

  3. Konwertuj zapytanie SQL Server na MySQL

  4. Moje zapytanie Wybierz SUMA zwraca wartość null. Powinien zwrócić 0

  5. Tabele SQL Server:jaka jest różnica między @, # i ##?