Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Tự động xóa các giao dịch bị quên trong MS SQL Server

Giới thiệu

Trường hợp này thường xảy ra khi một giao dịch MS SQL Server bị bộ khởi tạo quên. Ví dụ tốt nhất sẽ là như sau:một tập lệnh được thực thi trong SSMS, thông qua lệnh ‘begin tran’, bắt đầu một giao dịch và một lỗi xảy ra; tuy nhiên, ‘commit’ hoặc ‘rollback’ không đi qua và trình khởi tạo thực thi đã để lại truy vấn này trong một thời gian dài. Do đó, ngày càng có nhiều biến động hơn xuất hiện khi nói đến việc chặn các truy vấn yêu cầu quyền truy cập vào các tài nguyên đã đóng (bảng và tài nguyên máy chủ như RAM, CPU và hệ thống đầu vào).

Trong bài viết này, chúng tôi sẽ xem xét một trong những cách bạn có thể tự động hóa quy trình xóa giao dịch bị lãng quên.

Giải pháp

Hãy định nghĩa một giao dịch bị lãng quên là một giao dịch đang hoạt động (hiện đang được thực hiện), trong một khoảng thời gian T đủ lớn, không có truy vấn nào đang hoạt động (hiện đang được thực hiện).

Dưới đây là thuật toán chung để xóa các giao dịch như vậy:

  1. Tạo một bảng để lưu trữ và phân tích thông tin về các giao dịch hiện bị lãng quên cũng như một bảng để sắp xếp và lưu trữ các giao dịch đã chọn từ bảng đầu tiên bằng các thao tác xóa.
  2. Thu thập thông tin (các giao dịch và phiên của chúng không có truy vấn, tức là các giao dịch đã được thực hiện và bị quên trong một khoảng thời gian cụ thể T.
  3. Làm mới bảng chứa tất cả các giao dịch hiện đã bị quên mà chúng tôi đã thực hiện ở bước 1 (nếu một giao dịch bị quên có truy vấn đang hoạt động thì giao dịch đó sẽ bị xóa khỏi bảng này).
  4. Truy xuất các phiên mà chúng ta cần loại bỏ (một phiên có ít nhất một giao dịch đã bị bỏ quên trong bảng từ bước 1 K lần trở lên và phiên đó có một truy vấn đang hoạt động bị thiếu trong cùng một khoảng thời gian).
  5. Lưu trữ dữ liệu mà chúng tôi sẽ xóa (thông tin chi tiết về các phiên, kết nối và giao dịch sẽ bị hủy).
  6. Đang xóa các phiên đã chọn.
  7. Xóa các mục đã xử lý cùng với những mục không thể xóa và đã có trong bảng từ bước 1 quá lâu.

Bây giờ, hãy xem cách chúng tôi có thể triển khai thuật toán này.
Trước hết, chúng tôi sẽ cần tạo một bảng để lưu trữ và phân tích thông tin về tất cả các giao dịch hiện đang bị lãng quên:

USE [DB_NAME]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [srv].[SessionTran](
	[SessionID] [int] NOT NULL,
	[TransactionID] [bigint] NOT NULL,
	[CountTranNotRequest] [tinyint] NOT NULL,
	[CountSessionNotRequest] [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
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [srv].[SessionTran] ADD  CONSTRAINT [DF_SessionTran_Count]  DEFAULT ((0)) FOR [CountTranNotRequest]
GO

ALTER TABLE [srv].[SessionTran] ADD  CONSTRAINT [DF_SessionTran_CountSessionNotRequest]  DEFAULT ((0)) FOR [CountSessionNotRequest]
GO

ALTER TABLE [srv].[SessionTran] ADD  CONSTRAINT [DF_SessionTran_InsertUTCDate]  DEFAULT (getutcdate()) FOR [InsertUTCDate]
GO

ALTER TABLE [srv].[SessionTran] ADD  CONSTRAINT [DF_SessionTran_UpdateUTCDate]  DEFAULT (getutcdate()) FOR [UpdateUTCDate]
GO

Đây:

1) SessionID - mã định danh phiên
2) TransactionID - mã định danh giao dịch bị quên
3) CountTranNotRequest - số lần một giao dịch đã được đăng ký là bị quên
4) CountSessionNotRequest - số lần một phiên mà không có truy vấn hoạt động đã được đăng ký và có một giao dịch bị quên
5) TransactionBeginTime - ngày và giờ bắt đầu giao dịch bị lãng quên
6) InsertUTCDate - ngày và giờ tạo mục nhập (UTC)
7) UpdateUTCDate - ngày và giờ cập nhật mục nhập (UTC)

Tiếp theo, chúng tôi sẽ tạo một bảng để lưu trữ và sắp xếp các giao dịch từ bảng đầu tiên bằng các hành động xóa:

[expand title =” “]

USE [DB_NAME]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE 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,
	[reads] [bigint] NOT NULL,
	[writes] [bigint] NOT NULL,
	[logical_reads] [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] [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] [uniqueidentifier] 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,
	[CountSessionNotRequest] [tinyint] NOT NULL,
	[InsertUTCDate] [datetime] NOT NULL,
 CONSTRAINT [PK_KillSession] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (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]
GO

ALTER TABLE [srv].[KillSession] ADD  CONSTRAINT [DF_KillSession_InsertUTCDate]  DEFAULT (getutcdate()) FOR [InsertUTCDate]
GO

[/ mở rộng]

Tại đây, tất cả các trường được lấy từ biểu diễn hệ thống ‘sys.dm_exec_sessions’ và ‘sys.dm_exec_connections’ và ‘InsertUTCDate’ chỉ định thời gian UTC mà mục nhập được tạo.

Sau đó, để hoàn thành các bước còn lại, hãy triển khai quy trình được lưu trữ [srv]. [AutoKillSessionTranBegin] như sau:

[expand title =” “]

USE [DB_NAME]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE   PROCEDURE [srv].[AutoKillSessionTranBegin]
	@minuteOld int, --age of the executed transaction (T min.)
	@countIsNotRequests int --amount of times it has been placed into the table (K)
AS
BEGIN
	SET NOCOUNT ON;
	SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

    	declare @tbl table (
						SessionID int,
						TransactionID bigint,
						IsSessionNotRequest bit,
						TransactionBeginTime datetime
					   );
	
	--retrieving information (transactions and theirs session which have no requests, i.e, transactions that were initiated and forgotten)
	insert into @tbl (
						SessionID,
						TransactionID,
						IsSessionNotRequest,
						TransactionBeginTime
					 )
	select t.[session_id] as SessionID
		 , t.[transaction_id] as TransactionID
		 , case when exists(select top(1) 1 from sys.dm_exec_requests as r where r.[session_id]=t.[session_id]) then 0 else 1 end as IsSessionNotRequest
		 , (select top(1) ta.[transaction_begin_time] from sys.dm_tran_active_transactions as ta where ta.[transaction_id]=t.[transaction_id]) as TransactionBeginTime
	from sys.dm_tran_session_transactions as t
	where t.[is_user_transaction]=1
	and not exists(select top(1) 1 from sys.dm_exec_requests as r where r.[transaction_id]=t.[transaction_id]);
	
	--refreshing the table containing all initiated transactions with no requests
	;merge srv.SessionTran as st
	using @tbl as t
	on st.[SessionID]=t.[SessionID] and st.[TransactionID]=t.[TransactionID]
	when matched then
		update set [UpdateUTCDate]			= getUTCDate()
				 , [CountTranNotRequest]	= st.[CountTranNotRequest]+1			
				 , [CountSessionNotRequest]	= case when (t.[IsSessionNotRequest]=1) then (st.[CountSessionNotRequest]+1) else 0 end
				 , [TransactionBeginTime]	= t.[TransactionBeginTime]
	when not matched by target then
		insert (
				[SessionID]
				,[TransactionID]
				,[TransactionBeginTime]
			   )
		values (
				t.[SessionID]
				,t.[TransactionID]
				,t.[TransactionBeginTime]
			   )
	when not matched by source then delete;

	--list of sessions which need to be deleted (those that contain forgotten transactions)
	declare @kills table (
							SessionID int
						 );

	--детальная информация для архива
	declare @kills_copy table (
							SessionID int,
							TransactionID bigint,
							CountTranNotRequest tinyint,
							CountSessionNotRequest tinyint,
							TransactionBeginTime datetime
						 )

	--gathering the sessions we need to kill
	--a session has at least one transaction which was marked as having no requests @countIsNotRequests times 
        --and this session was marked as having no active requests the same amount of times 
	insert into @kills_copy	(
							SessionID,
							TransactionID,
							CountTranNotRequest,
							CountSessionNotRequest,
							TransactionBeginTime
						 )
	select SessionID,
		   TransactionID,
		   CountTranNotRequest,
		   CountSessionNotRequest,
		   TransactionBeginTime
	from srv.SessionTran
	where [CountTranNotRequest]>[email protected]
	  and [CountSessionNotRequest]>[email protected]
	  and [TransactionBeginTime]<=DateAdd(minute,[email protected],GetDate());

	  --archiving the data we need to delete (details on the sessions to be deleted, connections and transactions)
	  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_scheduled_time]
           ,[total_elapsed_time]
           ,[endpoint_id]
           ,[last_request_start_time]
           ,[last_request_end_time]
           ,[reads]
           ,[writes]
           ,[logical_reads]
           ,[is_user_process]
           ,[text_size]
           ,[language]
           ,[date_format]
           ,[date_first]
           ,[quoted_identifier]
           ,[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_count]
           ,[prev_error]
           ,[original_security_id]
           ,[original_login_name]
           ,[last_successful_logon]
           ,[last_unsuccessful_logon]
           ,[unsuccessful_logons]
           ,[group_id]
           ,[database_id]
           ,[authenticating_database_id]
           ,[open_transaction_count]
           ,[most_recent_session_id]
           ,[connect_time]
           ,[net_transport]
           ,[protocol_type]
           ,[protocol_version]
           ,[encrypt_option]
           ,[auth_scheme]
           ,[node_affinity]
           ,[num_reads]
           ,[num_writes]
           ,[last_read]
           ,[last_write]
           ,[net_packet_size]
           ,[client_net_address]
           ,[client_tcp_port]
           ,[local_net_address]
           ,[local_tcp_port]
           ,[connection_id]
           ,[parent_connection_id]
           ,[most_recent_sql_handle]
           ,[LastTSQL]
           ,[transaction_begin_time]
           ,[CountTranNotRequest]
           ,[CountSessionNotRequest])
	select ES.[session_id]
           ,kc.[TransactionID]
           ,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.[last_request_start_time]
           ,ES.[last_request_end_time]
           ,ES.[reads]
           ,ES.[writes]
           ,ES.[logical_reads]
           ,ES.[is_user_process]
           ,ES.[text_size]
           ,ES.[language]
           ,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]
           ,ES.[prev_error]
           ,ES.[original_security_id]
           ,ES.[original_login_name]
           ,ES.[last_successful_logon]
           ,ES.[last_unsuccessful_logon]
           ,ES.[unsuccessful_logons]
           ,ES.[group_id]
           ,ES.[database_id]
           ,ES.[authenticating_database_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]
           ,(select top(1) text from sys.dm_exec_sql_text(EC.[most_recent_sql_handle])) as [LastTSQL]
           ,kc.[TransactionBeginTime]
           ,kc.[CountTranNotRequest]
           ,kc.[CountSessionNotRequest]
	from @kills_copy as kc
	inner join sys.dm_exec_sessions ES with(readuncommitted) on kc.[SessionID]=ES.[session_id]
	inner join sys.dm_exec_connections EC  with(readuncommitted) on EC.session_id = ES.session_id;

	--gathering sessions
	insert into @kills (
							SessionID
						 )
	select [SessionID]
	from @kills_copy
	group by [SessionID];
	
	declare @SessionID int;

	--deleting sessions
	while(exists(select top(1) 1 from @kills))
	begin
		select top(1)
		@SessionID=[SessionID]
		from @kills;
    
    BEGIN TRY
		EXEC sp_executesql N'kill @SessionID',
						   N'@SessionID INT',
						   @SessionID;
    END TRY
    BEGIN CATCH
    END CATCH

		delete from @kills
		where [SessionID][email protected];
	end

	select st.[SessionID]
		  ,st.[TransactionID]
		  into #tbl
	from srv.SessionTran as st
	where st.[CountTranNotRequest]>=250
	   or st.[CountSessionNotRequest]>=250
	   or exists(select top(1) 1 from @kills_copy kc where kc.[SessionID]=st.[SessionID]);

	--Deleting the processed entries along with those that cannot be removed and have been in the table for too long
	delete from st
	from #tbl as t
	inner join srv.SessionTran as st on t.[SessionID]	 =st.[SessionID]
									and t.[TransactionID]=st.[TransactionID];

	drop table #tbl;
END
GO

[/ mở rộng]

Bước 7 của thuật toán được thực hiện thông qua một trong hai bộ đếm này - CountTranNotRequest hoặc CountSessionNotRequest - đạt đến giá trị 250.

Kết quả

Trong bài viết này, chúng tôi đã xem xét việc triển khai một quy trình tự động xóa các giao dịch bị lãng quên.

Phương pháp này cho phép chúng tôi tự động hóa quá trình xóa giao dịch bị lãng quên. Điều này dẫn đến việc giảm hoặc ngừng tăng trưởng dao động trong việc chặn được tạo ra bởi các giao dịch như vậy. Vì vậy, hiệu suất DBMS được bảo vệ khỏi các hành động có thể dẫn đến các giao dịch bị lãng quên.

Nguồn:

»Sys.dm_exec_requests
» sys.dm_tran_active_transactions
»sys.dm_tran_session_transactions
» sys.dm_exec_sql_text
»sys.dm_exec_sessions
» sys.dm_exec_connections
»KILL


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách lưu trữ hình ảnh trong cột bảng cơ sở dữ liệu SQL Server

  2. T-SQL Subquery Max (Date) và Joins

  3. SQL Server:Chỉ CHỌN các hàng có MAX (DATE)

  4. Loại bỏ và giảm các phạm vi ngày trùng lặp

  5. SQL Server - thiếu NATURAL JOIN / x JOIN y USING (trường)