sql >> Databáze >  >> RDS >> Sqlserver

Automatické mazání zapomenutých transakcí v MS SQL Server

Úvod

Často se stává, že iniciátor transakce MS SQL Server zapomene. Nejlepší příklad by byl následující:v SSMS je spuštěn skript, který prostřednictvím instrukce „begin tran“ zahájí transakci a dojde k chybě; „commit“ nebo „rollback“ však neprojdou a iniciátor provedení tento dotaz na dlouhou dobu opustil. V důsledku toho se objevuje stále větší fluktuace, pokud jde o blokování dotazů, které požadují přístup k uzavřeným zdrojům (tabulkám a zdrojům serveru, jako je RAM, CPU a vstupně-výstupní systém).

V tomto článku se podíváme na jeden ze způsobů, jak můžete automatizovat proces smazání zapomenuté transakce.

Řešení

Definujme zapomenutou transakci jako aktivní (aktuálně prováděnou) transakci, která během dostatečně dlouhého časového úseku T nemá žádné aktivní (aktuálně prováděné) dotazy.

Zde je obecný algoritmus pro mazání takových transakcí:

  1. Vytvoření tabulky pro ukládání a analýzu informací o aktuálně zapomenutých transakcích a také tabulky pro třídění a archivaci transakcí vybraných z první tabulky pomocí akcí mazání.
  2. Shromažďování informací (transakce a jejich relace, které nemají žádné dotazy, tj. transakce, které byly provedeny a zapomenuty v určeném časovém období T.
  3. Obnovení tabulky obsahující všechny aktuálně zapomenuté transakce, které jsme získali v kroku 1 (pokud zapomenutá transakce získala aktivní dotaz, bude taková transakce z této tabulky odstraněna).
  4. Načítání relací, které potřebujeme ukončit (relace obsahuje alespoň jednu transakci, která byla v kroku 1 K nebo vícekrát umístěna jako zapomenutá a v relaci stejně často chyběl aktivní dotaz).
  5. li>
  6. Archivace dat, která se chystáme smazat (podrobnosti o relacích, připojeních a transakcích, které budou zrušeny).
  7. Smazání vybraných relací.
  8. Odstranění zpracovaných záznamů spolu s těmi, které nelze odstranit a jsou v tabulce z kroku 1 příliš dlouho.

Nyní se podívejme, jak můžeme implementovat tento algoritmus.
Nejprve musíme vytvořit tabulku pro ukládání a analýzu informací o všech aktuálně zapomenutých transakcích:

POUŽÍVEJTE [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[SessionTran]( [ID relace] [int] NENÍ NULL, [ID transakce] [bigint] NENÍ NULL, [CountStranNotRequest] [estinyint] [SessionTran] ] [tinyint] NENÍ NULL, [TransactionBeginTime] [datetime] NOT NULL, [InsertUTCDate] [datetime] NOT NULL, [UpdateUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_SessionTran] PRIMÁRNÍ KLÍČ SE SLUSTROVANÝ ([ID relace] ASC] ASC)WITH (PAD_INDEX =VYPNUTO, STATISTICS_NORECOMPUTE =VYPNUTO, IGNORE_DUP_KEY =VYPNUTO, ALLOW_ROW_LOCKS =ZAPNUTO, ALLOW_PAGE_LOCKS =ZAPNUTO) ZAPNUTO [PRIMÁRNÍ]) NA [PRIMARY]NA [PRIMARY]BRANKÁŘSKÉ TABULCE [srv] DETRVESULT (CONTFADSessionCount_Tran].[CONTFADSessionCount_TRV 0)) PRO [CountTranNotRequest]TABULKA BRANKA [srv].[SessionTran] PŘIDAT OMEZENÍ [DF_SessionTran_CountSessionNotRequest] VÝCHOZÍ ((0)) PRO [CountSessionNotRequest]TABULKA BRANKA [srv].[Session DETERTUTCDu_datum] CONSTRANTUTCDDran_datum CONSTRANTUT [TFADGETDF ADDCran_datum] ) PRO [InsertUTCDate]TABULKA BRANKA [srv].[Session Tran] PŘIDAT OMEZENÍ [DF_SessionTran_UpdateUTCDate] VÝCHOZÍ (getutcdate()) PRO [UpdateUTCDate]PŘEJÍT

Zde:

1) SessionID — identifikátor relace
2) TransactionID — zapomenutý identifikátor transakce
3) CountTranNotRequest — kolikrát byla transakce zaregistrována jako zapomenutá
4) CountSessionNotRequest — kolikrát relace bez aktivních dotazů byl zaregistrován a měl zapomenutou transakci
5) TransactionBeginTime — datum a čas zahájení zapomenuté transakce
6) InsertUTCDate — datum a čas vytvoření záznamu (UTC)
7) UpdateUTCDate — datum a čas aktualizace záznamu (UTC)

Dále vytvoříme tabulku k archivaci a seřadíme transakce z první tabulky podle akcí odstranění:

[rozbalit název =”Kód “]

POUŽÍVEJTE [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[KillSession]( [ID] [int] IDENTITY(1,1) NENÍ NULL, [id_relace] [smallint] NENÍ NULL, [id_transakce] [bigint_id] ] NOT NULL, [login_time] [datetime] NOT NULL, [host_name] [nvarchar](128) NULL, [program_name] [nvarchar](128) NULL, [host_process_id] [int] NULL, [client_version] [int] NULL , [název_klientského_rozhraní] [nvarchar](32) NULL, [id_zabezpečení] [varbinary](85) NOT NULL, [login_name] [nvarchar](128) NOT NULL, [nt_domain] [nvarchar](128) NULL, [nt_user_name] [nvarchar](128) NULL, [stav] [nvarchar](30) NOT NULL, [context_info] [varbinary](128) NULL, [cpu_time] [int] NOT NULL, [memory_useage] [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, [reads] [bigint] NOT NULL NULL, [zapisuje] [bigint] NOT NULL, [logické_čtení] [bigint] NOT NULL, [is_user_process] [bit] NOT NULL, [text_size] [int] NOT NULL, [language] [nvarchar](128) NULL, [date_format] [nvarchar](3) NULL, [date_first] [smallint] NOT NULL, [quoted_identifier] [bit] NOT 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_unsuccessful_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] , [doba_připojení] [ 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, [node_affinity] [smallint] NULL, [num_reads] [int] NULL, [num_writes] [int] NULL, [poslední_čtení] [datetime] NULL, [last_write] [datetime] NULL, [net_packet_size] [ 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] [jednoznačný identifikátor] NULL, [id_parent_connection_id] [uniqueidentifier] NULL, [most_recent_sql_handle] [varbinary](64) NULL, [LastTSQL] [nvarchar](max) NULL, [time_begin_time] [datetime] NOT NULL, [CountTranNotRequest] [estinyintRequest] [estinyintRequest] ] [tinyint] NOT NULL, [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_KillSession] PRIMÁRNÍ KLÍČ SE SLUSTROVANÝ ( [ID] ASC)WITH (PAD_INDEX =VYPNUTO, STATISTICS_NORECOMPUTE =VYPNUTO, IGNORE =_DUP_KEY =VYPNUTO, VYPNUTO ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMÁRNÍ]) NA [PRIMÁRNÍ] TEXTIMAGE_ON [PRIMÁRNÍ] TABULKA BRANKA [srv].[KillSession] PŘIDAT OMEZENÍ [DF_KillSession_InsertUTCDate] VÝCHOZÍ (getutcdate()) PRO [Ins. 

[/expand]

Zde jsou všechna pole převzata ze systémových reprezentací ‚sys.dm_exec_sessions‘ a ‚sys.dm_exec_connections‘ a ‚InsertUTCDate‘ určuje čas UTC, kdy byl záznam vytvořen.

Poté, abychom dokončili zbývající kroky, implementujme uloženou proceduru [srv].[AutoKillSessionTranBegin] takto:

[rozbalit název =”Kód “]

POUŽÍVEJTE [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [srv].[AutoKillSessionTranBegin] @minuteOld int, --stáří provedené transakce (T min.) @countIsNotRequests int --počet, kolikrát byla vložena tabulka (K)ASBEGIN SET NOCOUNT ON; NASTAVIT ÚROVEŇ IZOLACE TRANSAKCE PŘEČTENÁ NEZÁVAZNĚ; deklarovat tabulku @tbl (SessionID int, TransactionID bigint, IsSessionNotRequest bit, TransactionBeginTime datetime ); --načtení informací (transakce a jejich relace, které nemají žádné požadavky, tj. transakce, které byly zahájeny a zapomenuty) vložit do @tbl (ID_relace, ID_transakce, IsSessionNotRequest, TransactionBeginTime) vybrat t[id_relace] jako ID_relace, t.[id_transakce] jako TransactionID , případ, kdy existuje (vyberte top(1) 1 ze sys.dm_exec_requests jako r, kde r.[id_relace]=t[id_relace]), pak 0 jinak 1 skončí jako IsSessionNotRequest , (vyberte top(1) ta.[transaction_begin_time ] ze sys.dm_tran_active_transactions jako ta, kde ta.[id_transakce]=t.[id_transakce]) jako TransactionBeginTime ze sys.dm_tran_session_transactions jako t, kde t.[is_user_transaction]=1 a neexistuje (vyberte top(1) 1 ze sys.dmquest jako r kde r.[id_transakce]=t.[id_transakce]); --obnovení tabulky obsahující všechny zahájené transakce bez požadavků; sloučit srv.SessionTran jako st pomocí @tbl jako t na st.[ID relace]=t.[ID relace] a st.[ID_transakce]=t.[ID_transakce], když se shodují potom aktualizujte sadu [UpdateUTCDate] =getUTCDate() , [CountTranNotRequest] =st.[CountTranNotRequest]+1 , [CountSessionNotRequest] =případ, kdy (t.[IsSessionNotRequest]=1) pak (st.[CountSessionNotRequest]+1) jinak 0 end , [TransactionBeginTime] =t.[TransactionBeginTime], pokud se neshoduje s cílem, pak vložte ( [SessionID] ,[TransactionID] ,[TransactionBeginTime] ) hodnoty ( t.[SessionID] ,t.[TransactionID] ,t.[TransactionBeginTime] ) pokud zdroj neodpovídá, pak smazat; --seznam relací, které je třeba smazat (ty, které obsahují zapomenuté transakce) deklarovat tabulku @kills (SessionID int); --детальная информация для архива deklarovat tabulku @kills_copy (SessionID int, TransactionID bigint, CountTranNotRequest tinyint, CountSessionNotRequest kill, --a mít relaci tinyint, Transaction) --a mít označenou relaci na nejkratší čas transakce požaduje @countIsNotRequests krát -- a tato relace byla označena jako bez aktivních požadavků tolikrát, kolikrát se vloží do @kills_copy ( SessionID, TransactionID, CountTranNotRequest, CountSessionNotRequest, TransactionBeginTime ) vyberte SessionID, TransactionID, CountessionTranNotRequest, CountessionTrannotrvRequest.SessionTranssionNotRequest. kde [CountTranNotRequest]>[email protected] a [CountSessionNotRequest]>[email protected] a [TransactionBeginTime]<=DateAdd(minute,[email protected],GetDate()); --archivace dat, která potřebujeme smazat (podrobnosti o relacích, které mají být smazány, připojení a transakce) INSERT INTO [srv].[KillSession] ([session_id] ,[transaction_id] ,[login_time] ,[host_name] ,[program_name ] ,[host_process_id] ,[client_version] ,[client_interface_name] ,[security_id] ,[login_name] ,[nt_domain] ,[nt_user_name] ,[status] ,[context_info] ,[cpu_time] ,[memory_to_usage] ,[memory_total_usage] [total_elapsed_time] ,[end_id_id] ,[last_request_start_time] ,[last_request_end_time] ,[reads] ,[writes] ,[logic_reads] ,[is_user_process] ,[text_size] ,[language] ,[st_date_format ] ,[arithabort] ,[ansi_null_dflt_on] ,[ansi_defaults] ,[ansi_warnings] ,[ansi_padding] ,[ansi_nulls] ,[concat_null_yields_null] ,[transaction_isolation_level] ,[lock_timeout] ,[deadlock_priority] ,[název],[řada_originální_chyba] ,[prevgin_error] last_successful_logon] ,[last_unsuccessful_logon] ,[unsuccessful_logons] ,[group_id] ,[database_id] ,[authenticating_database_id] ,[open_transaction_count] ,[most_recent_session_id] ,[to_col_type]transition] ,[colop_type]proport] ,[schéma_autorizace] ,[afinita_uzlu] ,[počet_čtení] ,[počet_zápisů] ,[poslední_čtení] ,[poslední_zápis] ,[net_packet_size] ,[client_net_address] ,[client_tcp_port] ,[local_n et_address] ,[local_tcp_port] ,[id_připojení] ,[id_rodičovského_připojení] ,[most_recent_sql_handle] ,[LastTSQL] ,[čas_začátku_transakce] ,[CountTranNotRequest] ,[CountSession_id [PočetSession]]),[ESssionNotRequest,kID]), selectNot. [login_time] ,ES.[název_hostitele] ,ES.[název_programu] ,ES.[id_procesu_hostitele] ,ES.[verze_klienta] ,ES.[název_rozhraní_klienta] ,ES[id_zabezpečení] ,ES.[přihlašovací_jméno] ,ES.[nt_domain ] ,ES.[nt_user_name] ,ES.[stav] ,ES.[context_info] ,ES.[cpu_time] ,ES.[memory_usage] ,ES.[total_scheduled_time] ,ES.[total_elapsed_time] ,ES.[endpoint_id] , ES.[last_request_start_time] ,ES.[last_request_end_time] ,ES.[čtení] ,ES.[zápisy] ,ES.[logické_čtení] ,ES.[is_user_process ] ,ES.[velikost_textu] ,ES.[jazyk] ,ES.[formát_data] ,ES.[první_datum] ,ES.[identifikátor citátu] ,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.[transaction_isolation_level] ,ES.[lock_timeout] ,ES[deadlock_priority] ,ES.[row_count] ,ES. [prev_error] ,ES.[original_security_id] ,ES.[original_login_name] ,ES.[last_successful_logon] ,ES.[last_unsuccessful_logon] ,ES.[unsuccessful_logons] ,ES.[id_skupiny] ,ES.[database_idating_idating] ,ES.[database_idating_idating] ,ES.[last_unsuccessful_logon] ,ES.[unsuccessful_logons] ,ES.[id_skupiny] ,ES.[database_idating_id] ] ,ES.[open_transaction_count] ,EC.[most_recent_session_id] ,EC.[connect_time] ,EC.[net_transport] ,EC.[protocol_type] ,EC.[protocol_version ] ,EC.[encrypt_option] ,EC.[auth_scheme] ,EC.[node_affinity] ,EC.[num_reads] ,EC.[num_writes] ,EC.[last_read] ,EC.[last_write] ,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] ,(vyberte top(1) text z sys.dm_exec_sql_text(EC.[most_recent_sql_handle])) jako [LastTSQL] ,kc.[TransactionBeginTime] ,kc.[CountTranNotRequest] ,kc.[CountSessionNotRequest] od @kills_copy jako kmdccom_vnitřní spojení EScstedses. .[ID relace]=ES.[id_relace] vnitřní spojení sys.dm_exec_connections EC with(readuncommitted) na EC.session_id =ES.session_id; --gathering sessions vložit do @kills ( SessionID ) vybrat [SessionID] ze skupiny @kills_copy podle [SessionID]; deklarovat @SessionID int; --mazání relací while(exists(select top(1) 1 from @kills)) begin select top(1) @SessionID=[ID relace] z @kills; ZAČNĚTE ZKUSTE EXEC sp_executesql N'kill @SessionID', N'@SessionID INT', @SessionID; KONEC ZKUSTE ZAČÁTEK ÚLOVEK KONEC ÚLOVEK smazat z @kills kde [ID relace][email protected]; end select st.[SessionID] ,st.[TransactionID] do #tbl ze srv.SessionTran jako st kde st.[CountTranNotRequest]>=250 nebo st.[CountSessionNotRequest]>=250 nebo existuje(select top(1) 1 from @kills_copy kc kde kc.[ID relace]=st.[ID relace]); --Odstranění zpracovaných záznamů spolu s těmi, které nelze odstranit a jsou v tabulce příliš dlouho delete from st from #tbl as t internal join srv.SessionTran as st on t.[SessionID] =st.[SessionID] and t.[ID_transakce]=st.[ID_transakce]; drop table #tbl;ENDGO

[/expand]

Krok 7 algoritmu je implementován prostřednictvím jednoho z těchto dvou čítačů – CountTranNotRequest nebo CountSessionNotRequest – dosahující hodnoty 250.

Výsledek

V tomto článku jsme se podívali na implementaci procesu, který automaticky odstraňuje zapomenuté transakce.

Tato metoda nám umožňuje automatizovat proces vymazání zapomenuté transakce. To má za následek snížení nebo zastavení nárůstu fluktuace v blokování způsobeného těmito transakcemi. Výkon DBMS je tedy chráněn před akcemi, které mohou vést k zapomenutým transakcím.

Zdroje:

» sys.dm_exec_requests
» sys.dm_tran_active_transactions
» sys.dm_tran_session_transactions
» sys.dm_exec_sql_text
» sys.dm_exec_sessions
» c
sys.d.


  1. Oprava „ERROR 1054 (42S22):Neznámý sloupec „colname“ v „klauzuli objednávky“ v MariaDB

  2. Knihovna není načtena:chyba libmysqlclient.16.dylib při pokusu o spuštění „rails serveru“ v OS X 10.6 s gem mysql2

  3. Nastavení Django a PostgreSQL na dvou různých instancích EC2

  4. Nelze otevřít databázi v režimu čtení/zápisu