Vous êtes ici :
Une autre approche ici pour éviter des verrous bloquants (voir l’autre script « Kill lead blocker automatique ») : déconnecter toutes les transactions interminables, qu’elles soient bloquantes ou pas (si elles ne le sont pas, elles peuvent le devenir !). C’est brutal et c’est bien loin d’être une véritable solution, le problème provenant de l’applicatif, mais cela m’a déjà servi en pansement temporaire pour une application qui « oublie » de fermer ses transactions.
Dans le script, la durée des transactions à déconnecter est de 30 minutes, à configurer. On peut aussi filtrer sur une base en particulier. Et une table de log, à créer dans msdb, journalise les déconnexions effectuées.
Transact-SQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
/*------------------------------------------------------------------- [SCRIPT] automatic kill long transactions [DATABASE] master [DESCRIPTION] use it as SQL Agent Job [MAJ PAR] DATAFLY - Arian Papillon [DATEMAJ] 20190122 -------------------------------------------------------------------*/ /* -- Create log table in msdb -- USE [msdb] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[LongTransactionKillLog]( [Id] [int] IDENTITY(1,1) NOT NULL, [event_time] [datetime2](0) NULL, [session_id] [int] NULL, [client_net_address] [varchar](20) NULL, [login_name] [sysname] NOT NULL, [host_name] [sysname] NOT NULL, [program_name] [varchar](200) NULL, [duration] [varchar](20) NULL, [transaction_begin_time] [datetime2](0) NULL, [last_read] [datetime2](0) NULL, [last_write] [datetime2](0) NULL ) ON [PRIMARY] GO ALTER TABLE [dbo].[LongTransactionKillLog] ADD DEFAULT (sysdatetime()) FOR [event_time] GO */ DECLARE @SpidToKill INT, @SQLCmd VARCHAR(200); WHILE (1=1) BEGIN SET @SpidToKill = NULL SELECT TOP (1) @SpidToKill = s.session_id FROM sys.dm_tran_session_transactions s INNER JOIN sys.dm_tran_database_transactions dt ON s.transaction_id = dt.transaction_id WHERE database_transaction_log_record_count > 0 -- configure filters here : duration threshold in seconds, database id AND DATEDIFF(SECOND, database_transaction_begin_time, GETDATE()) > 1800 -- 30 mn -- AND dt.database_id = 2 OPTION (RECOMPILE); SELECT @SpidToKill; IF @SpidToKill IS NULL BEGIN BREAK; END; INSERT msdb.dbo.LongTransactionKillLog ( session_id, client_net_address, login_name, host_name, program_name, duration, transaction_begin_time, last_read, last_write ) SELECT s.session_id, c.client_net_address, se.login_name, se.host_name, se.program_name, Duration = CASE WHEN DATEDIFF(SECOND, a.transaction_begin_time, GETDATE()) >= 3600 THEN CAST(CAST(DATEDIFF(SECOND, a.transaction_begin_time, GETDATE()) / 3600. AS DECIMAL(7, 2)) AS VARCHAR) + ' Hr' WHEN DATEDIFF(SECOND, a.transaction_begin_time, GETDATE()) >= 60 THEN CAST(CAST(DATEDIFF(SECOND, a.transaction_begin_time, GETDATE()) / 60. AS DECIMAL(7, 2)) AS VARCHAR) + ' Min' ELSE CAST(CAST(DATEDIFF(MILLISECOND, a.transaction_begin_time, GETDATE()) / 1000. AS DECIMAL(7, 2)) AS VARCHAR) + ' Sec' END, a.transaction_begin_time, c.last_read, c.last_write FROM sys.dm_tran_active_transactions a LEFT JOIN sys.dm_tran_session_transactions s ON a.transaction_id = s.transaction_id LEFT JOIN sys.[dm_exec_connections] c ON s.session_id = c.session_id LEFT JOIN sys.dm_exec_sessions se ON c.session_id = se.session_id LEFT JOIN sys.dm_tran_database_transactions dt ON a.transaction_id = dt.transaction_id LEFT JOIN sys.sysprocesses AS sp ON sp.spid = s.session_id WHERE dt.database_id = 2 AND s.session_id = @SpidToKill OPTION (RECOMPILE); SET @SQLCmd = 'KILL ' + CAST(@SpidToKill AS NVARCHAR(6)); EXEC (@SQLCmd); END; |
Table of Contents