sql >> Database >  >> RDS >> Sqlserver

Automatische verwijdering van vergeten transacties in MS SQL Server

Inleiding

Het is vaak het geval wanneer een MS SQL Server-transactie wordt vergeten door de initiatiefnemer. Het beste voorbeeld is het volgende:er wordt een script uitgevoerd in SSMS dat via de instructie ‘begin tran’ een transactie start en er een fout optreedt; 'commit' of 'rollback' gaan echter niet door en de initiator van de uitvoering heeft deze query lange tijd verlaten. Als gevolg hiervan treden er steeds meer fluctuaties op als het gaat om het blokkeren van de query's die toegang vragen tot afgesloten bronnen (tabellen en serverbronnen zoals RAM, CPU en het input-outputsysteem).

In dit artikel bekijken we een van de manieren waarop u het proces voor het verwijderen van vergeten transacties kunt automatiseren.

De oplossing

Laten we een vergeten transactie definiëren als een actieve (momenteel uitgevoerde) transactie die, gedurende een voldoende grote tijdspanne T, geen actieve (momenteel uitgevoerde) zoekopdrachten heeft.

Hier is het algemene algoritme voor het verwijderen van dergelijke transacties:

  1. Een tabel maken om informatie over momenteel vergeten transacties op te slaan en te analyseren, evenals een tabel om de geselecteerde transacties uit de eerste tabel te sorteren en te archiveren door middel van verwijderingsacties.
  2. Informatie verzamelen (transacties en hun sessies die geen vragen hebben, d.w.z. de transacties die zijn uitgevoerd en vergeten binnen een bepaalde tijdspanne T.
  3. De tabel vernieuwen met alle momenteel vergeten transacties die we in stap 1 hebben gekregen (als een vergeten transactie een actieve zoekopdracht heeft gekregen, wordt een dergelijke transactie uit deze tabel verwijderd).
  4. Het ophalen van de sessies die we moeten beëindigen (een sessie heeft ten minste één transactie die als vergeten in de tabel is geplaatst vanaf stap 1 K of meer keer en de sessie had hetzelfde aantal keren een ontbrekende actieve zoekopdracht).
  5. li>
  6. De gegevens archiveren die we gaan verwijderen (details over de sessies, verbindingen en transacties die worden afgebroken).
  7. De geselecteerde sessies verwijderen.
  8. Verwijderen van de verwerkte vermeldingen en de vermeldingen die niet kunnen worden verwijderd en die te lang in de tabel van stap 1 staan.

Laten we nu eens kijken hoe we dit algoritme kunnen implementeren.
Allereerst moeten we een tabel maken om de informatie over alle momenteel vergeten transacties op te slaan en te analyseren:

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, [CountTranNotRequest] [tinyint] NOT NULL, [CountTranNotRequest] ] [tinyint] NOT NULL, [TransactionBeginTime] [datetime] NOT NULL, [InsertUTCDate] [datetime] NOT NULL, [UpdateUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_SessionTran] PRIMARY KEY CLUSTERED ([SessionID] ASC, [TransactionID] ASC)MET (PAD_INDEX =UIT, STATISTICS_NORECOMPUTE =UIT, IGNORE_DUP_KEY =UIT, ALLOW_ROW_LOCKS =AAN, ALLOW_PAGE_LOCKS =AAN) AAN [PRIMAIR]) AAN [PRIMARY]GOALTER TABLE [srv].[SessionTran] TOEVOEGEN CONSTRAN [PRIMAIR] 0)) FOR [CountTranNotRequest]GOALTER TABLE [srv].[SessionTran] ADD CONSTRAINT [DF_SessionTran_CountSessionNotRequest] STANDAARD ((0)) FOR [CountSessionNotRequest]GOALTER TABLE [srv].[SessionTran] ADD-CONSINTTran [DF_SFAUTTRAAT] ) VOOR [InsertUTCDate]GOALTER TABLE [srv].[Sessie Tran] ADD CONSTRAINT [DF_SessionTran_UpdateUTCDate] STANDAARD (getutcdate()) VOOR [UpdateUTCDate]GO

Hier:

1) SessionID — sessie-ID
2) TransactionID — transactie-ID vergeten
3) CountTranNotRequest — het aantal keren dat een transactie is geregistreerd als vergeten
4) CountSessionNotRequest — het aantal keren dat een sessie zonder actieve zoekopdrachten is geregistreerd en had een vergeten transactie
5) TransactionBeginTime — datum en tijd van de initiatie van de vergeten transactie
6) InsertUTCDate — datum en tijd van aanmaak van invoer (UTC)
7) UpdateUTCDate — datum en tijd van invoerupdate (UTC)

Vervolgens maken we een tabel om de transacties van de eerste tabel te archiveren en te sorteren door middel van verwijderingsacties:

[titel uitbreiden =”Code "]

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, [host_name] [nvarchar](128) NULL, [program_name] [nvarchar](128) NULL, [host_process_id] [int] NULL, [client_version] [int] NULL , [client_interface_name] [nvarchar](32) NULL, [security_id] [varbinary](85) NOT NULL, [login_name] [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, [leest] [bigint] NOT NULL, [schrijft] [bigint] NOT NULL, [logical_reads] [bigint] NOT NULL, [is_user_process] [bit] NOT NULL, [text_size] [int] NOT NULL, [taal] [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] [datetime] NULL, [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 , [connect_time] [ 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, [last_read] [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] [unieke identificatie] 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, [CountSsionNot ] [tinyint] NOT NULL, [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_KillSession] PRIMAIRE SLEUTEL GECLUSTERD ( [ID] ASC)MET (PAD_INDEX =UIT, STATISTICS_NORECOMPUTE =UIT, IGNORE_DUP_KEY =UIT, ALLOW =_ROW ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]GOALTER TABLE [srv].[KillSession] ADD CONSTRAINT [DF_KillSession_InsertUTCDate] STANDAARD (getutcdate()) FOR [GOCdate] 

[/uitbreiden]

Hier worden alle velden overgenomen uit de systeemrepresentaties 'sys.dm_exec_sessions' en 'sys.dm_exec_connections', en 'InsertUTCDate' specificeert de UTC-tijd waarop het item is gemaakt.

Laten we, om de resterende stappen te voltooien, de [srv].[AutoKillSessionTranBegin] opgeslagen procedure als volgt implementeren:

[titel uitbreiden =”Code "]

GEBRUIK [DB_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [srv].[AutoKillSessionTranBegin] @minuteOld int, --leeftijd van de uitgevoerde transactie (T min.) @countIsNotRequests int --aantal keren dat het in de tabel (K)ASBEGIN STEL NOCOUNT IN; STEL HET TRANSACTIE-ISOLATIENIVEAU IN LEES NIET-BEVOEGD; declareer @tbl tabel ( SessionID int, TransactionID bigint, IsSessionNotRequest bit, TransactionBeginTime datetime ); --het ophalen van informatie (transacties en hun sessie die geen verzoeken hebben, d.w.z. transacties die zijn gestart en vergeten) invoegen in @tbl ( SessionID, TransactionID, IsSessionNotRequest, TransactionBeginTime ) selecteer t.[session_id] als SessionID , t.[transaction_id] als TransactionID , case wanneer bestaat (selecteer top(1) 1 van sys.dm_exec_requests als r waar r.[session_id]=t.[session_id]) dan 0 else 1 eindigt als IsSessionNotRequest , (selecteer top(1) ta.[transaction_begin_time ] van sys.dm_tran_active_transactions als ta waar ta.[transaction_id]=t.[transactie_id]) als TransactionBeginTime van sys.dm_tran_session_transactions als t waar t.[is_user_transaction]=1 en bestaat niet (selecteer top(1) 1 van sys.dm_exec_ als r waar r.[transactie_id]=t.[transactie_id]); --verversen van de tabel met alle gestarte transacties zonder verzoeken;merge srv.SessionTran als st met @tbl als t op st.[SessionID]=t.[SessionID] en st.[TransactionID]=t.[TransactionID] indien gematcht update vervolgens set [UpdateUTCDate] =getUTCDate() , [CountTranNotRequest] =st.[CountTranNotRequest]+1 , [CountSessionNotRequest] =geval wanneer (t.[IsSessionNotRequest]=1) then (st.[CountSessionNotRequest]+1) else 0 end , [TransactionBeginTime] =t.[TransactionBeginTime] wanneer niet overeenkomt met doel, voeg dan ( [SessionID] ,[TransactionID] ,[TransactionBeginTime] ) waarden in ( t.[SessionID] ,t.[TransactionID] ,t.[TransactionBeginTime] ) wanneer niet overeenkomt met de bron, verwijder dan; --lijst met sessies die moeten worden verwijderd (de sessies die vergeten transacties bevatten) declareer @kills-tabel ( SessionID int ); --детальная информация для архива declare @kills_copy table ( SessionID int, TransactionID bigint, CountTranNotRequest tinyint, CountSessionNotRequest tinyint, TransactionBeginTime datetime ) --het verzamelen van de sessies die we moeten beëindigen --een sessie heeft ten minste één transactie die is gemarkeerd als hebbende geen verzoeken @countIsNotRequests keer --en deze sessie is gemarkeerd als geen actieve verzoeken hebben, voeg hetzelfde aantal keren in @kills_copy ( SessionID, TransactionID, CountTranNotRequest, CountSessionNotRequest, TransactionBeginTime ) selecteer SessionID, TransactionID, CountTranNotRequest, CountSessionNotRequest, TransactionBeginTime van Tranv.Session waar [CountTranNotRequest]>[email protected] en [CountSessionNotRequest]>[email protected] en [TransactionBeginTime]<=DateAdd(minute,[email protected],GetDate()); --archiveren van de gegevens die we moeten verwijderen (details over de te verwijderen sessies, verbindingen en transacties) 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_usage] ,[total_total]_ [total_elapsed_time] ,[endpoint_id] ,[laatste_request_start_time] ,[laatste_request_end_time] ,[leest] ,[schrijft] ,[logische_lezingen] ,[is_user_process] ,[text_size] ,[taal] ,[quotdate_format] ,[date_ed_ed_identifier] ] ,[arithabort] ,[ansi_null_dflt_on] ,[ansi_defaults] ,[ansi_warnings] ,[ansi_padding] ,[ansi_nulls] ,[concat_null_yields_null] ,[transaction_isolation_level] ,[lock_timeout] ,[deadlock_name_priority] ,[row_count_er] _or] last_successful_logon] ,[laatste_unsuccessful_logon] ,[unsuccessful_logons] ,[group_id] ,[database_id] ,[authenticating_database_id] ,[open_transaction_count] ,[most_recent_session_id] ,[net_time] ,[net_time] , ,[auth_scheme] ,[node_affinity] ,[num_reads] ,[num_writes] ,[last_read] ,[laatste_write] ,[net_packet_size] ,[client_net_address] ,[client_tcp_port] ,[local_n et_address] ,[local_tcp_port] ,[connection_id] ,[parent_connection_id] ,[most_recent_sql_handle] ,[LastTSQL] ,[transaction_begin_time] ,[CountTranNotRequest] ,[CountSessionNotRequest] ,[CountSessionNotRequest[]) selecteer ES]. [login_time] ,ES.[host_name] ,ES.[program_name] ,ES.[host_process_id] ,ES.[client_version] ,ES.[client_interface_name] ,ES.[security_id] ,ES.[login_name] ,ES.[nt_domain ] ,ES.[nt_user_name] ,ES.[status] ,ES.[context_info] ,ES.[cpu_time] ,ES.[memory_usage] ,ES.[total_scheduled_time] ,ES.[total_elapsed_time] ,ES.[endpoint_id] , ES.[laatste_request_start_time] ,ES.[laatste_request_end_time] ,ES.[leest] ,ES.[schrijft] ,ES.[logische_lezingen] ,ES.[is_user_process ] ,ES.[text_size] ,ES.[taal] ,ES.[date_format] ,ES.[date_first] ,ES.[quoted_identifier] ,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] [prev_error] ,ES.[original_security_id] ,ES.[original_login_name] ,ES.[laatste_successful_logon] ,ES.[laatste_unsuccessful_logon] ,ES.[unsuccessful_logons] ,ES.[group_id] ,ES,[database_id] ] ,ES.[open_transaction_count] ,EC.[most_recent_session_id] ,EC.[connect_time] ,EC.[net_transport] ,EC.[protocol_type] ,EC.[protocol_versie ] ,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] ,(selecteer top(1) tekst uit sys.dm_exec_sql_text(EC.[most_recent_sql_handle])) as [LastTSQL] ,kc.[TransactionBeginTime] ,kc.[CountTranNotRequest] ,kc.[CountSessionNotRequest] van @kills_copy as kdm inner_exec_com .[SessionID]=ES.[session_id] inner join sys.dm_exec_connections EC with(readuncommitted) op EC.session_id =ES.session_id; --gathering session invoegen in @kills ( SessionID ) selecteer [SessionID] van @kills_copy group door [SessionID]; declareren @SessionID int; --sessies verwijderen while(exists(select top(1) 1 from @kills)) begin select top(1) @SessionID=[SessionID] van @kills; BEGIN PROBEER EXEC sp_executesql N'kill @SessionID', N'@SessionID INT', @SessionID; EINDE PROBEREN BEGIN CATCH END CATCH verwijderen uit @kills waar [SessionID][email protected]; end selecteer st.[SessionID] ,st.[TransactionID] in #tbl van srv.SessionTran as st waarbij st.[CountTranNotRequest]>=250 of st.[CountSessionNotRequest]>=250 of bestaat (select top(1) 1 from @kills_copy kc waarbij kc.[SessionID]=st.[SessionID]); --Verwijderen van de verwerkte vermeldingen samen met de vermeldingen die niet kunnen worden verwijderd en die te lang in de tabel hebben gestaan ​​delete from st from #tbl as t inner join srv.SessionTran as st on t.[SessionID] =st.[SessionID] en t.[Transactie-ID]=st.[Transactie-ID]; laat tafel vallen #tbl;ENDGO

[/uitbreiden]

Stap 7 van het algoritme wordt geïmplementeerd via een van deze twee tellers - CountTranNotRequest of CountSessionNotRequest - die een waarde van 250 bereikt.

Het resultaat

In dit artikel hebben we gekeken naar een implementatie van een proces waarmee vergeten transacties automatisch worden verwijderd.

Met deze methode kunnen we het proces voor het verwijderen van vergeten transacties automatiseren. Dit resulteert in het verminderen of stoppen van de fluctuatiegroei in de blokkering die door dergelijke transacties wordt veroorzaakt. De DBMS-prestaties zijn dus beschermd tegen acties die kunnen leiden tot vergeten transacties.

Bronnen:

» sys.dm_exec_requests
» sys.dm_tran_active_transactions
» sys.dm_tran_session_transactions
» sys.dm_exec_sql_text
» sys.dm_exec_sessions.dm» sys.dm_exec_sessions.dm»


  1. Hoe de eerste en laatste dag van de vorige maand (met tijdstempel) in SQL Server te krijgen

  2. Waarden splitsen over meerdere rijen

  3. Bekijk mijn presentatie 'Optimaliseren van Microsoft Access met SQL Server'

  4. Hoe te kiezen uit twee tabellen in MySQL, zelfs als niet alle rijen in de ene tabel correspondenten hebben in de andere?