Vous êtes ici :
Ce script permet de mettre en place une journalisation des verrous bloquants dans une table de la base msdb, via une notification d’évènements.
Il est basé sur une notification d’évènement sur le déclenchement du « blocked process report », configuré à 15 secondes : le message est transmis de manière asynchrone par le service broker et le rapport est stocké en XML dans la table msdb..BlockingEventsXML. La vue msdb..BlockingEvents permet de visualiser les informations au format tabulaire.
N’oubliez pas de purger la table de temps en temps…
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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
/*------------------------------------------------------------------- [SCRIPT] Blocked Process Report & Event Notification Installation Script [DATABASE] msdb [DESCRIPTION] Installe suivi des verrous supérieurs à 15 secondes [MAJ PAR] DATAFLY - Arian Papillon [DATEMAJ] 20190202 -------------------------------------------------------------------*/ -- Configurer le "blocked process threshold" à 15 secondes USE MASTER GO EXEC sys.sp_configure N'show', 1 RECONFIGURE GO EXEC sys.sp_configure N'blocked process threshold', 15 GO RECONFIGURE WITH OVERRIDE GO EXEC sys.sp_configure N'show', 0 RECONFIGURE GO -- Configurer le service broker et les objets dans msdb use [msdb] GO IF EXISTS ( SELECT * FROM sys.services WHERE name = 'NotifyBlockingService' ) DROP SERVICE NotifyBlockingService GO IF OBJECT_ID('[dbo].[NotifyBlockingQueue]') IS NOT NULL AND EXISTS ( SELECT * FROM sys.service_queues WHERE name = 'NotifyBlockingQueue' ) DROP QUEUE [dbo].[NotifyBlockingQueue] GO CREATE QUEUE NotifyBlockingQueue GO CREATE SERVICE NotifyBlockingService ON QUEUE NotifyBlockingQueue ([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification]) GO -- Table de journalisation USE [msdb] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[BlockingEventsXML]( [EventNumber] [int] IDENTITY(1,1) NOT NULL, [EventType] [nvarchar](256) NULL, [EventTime] [datetime] NULL, [EventData] [xml] NULL, PRIMARY KEY CLUSTERED ( [EventNumber] 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 IF OBJECT_ID(N'[dbo].[LogBlockingEvents]') IS NOT NULL AND OBJECTPROPERTY(OBJECT_ID(N'[dbo].[LogBlockingEvents]'), N'IsProcedure') = 1 DROP PROCEDURE [dbo].[LogBlockingEvents] GO -- Procédure stockée de journalisation SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[LogBlockingEvents] AS BEGIN SET NOCOUNT ON DECLARE @message_body XML , @message_type_name NVARCHAR(256) , @dialog UNIQUEIDENTIFIER; WHILE ( 1 = 1 ) BEGIN BEGIN TRANSACTION WAITFOR ( RECEIVE TOP ( 1 ) -- just handle one message at a time @message_type_name = message_type_name, --the type of message received @message_body = message_body, -- the message contents @dialog = conversation_handle -- the identifier of the dialog this message was received on FROM NotifyBlockingQueue ), TIMEOUT 2000; -- if the queue is empty for two seconds, give up and go away IF ( @@ROWCOUNT = 0 ) BEGIN ROLLBACK TRANSACTION; BREAK; END; IF ( @message_type_name = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog' ) BEGIN PRINT 'Fin du dialogue # ' + CAST(@dialog AS NVARCHAR(40)); END CONVERSATION @dialog; END; ELSE BEGIN INSERT INTO [dbo].[BlockingEventsXML] ( EventType , EventTime , EventData ) VALUES ( CAST(@message_body.query('/EVENT_INSTANCE/EventType/text()') AS NVARCHAR(256)) , CAST(CAST(@message_body.query('/EVENT_INSTANCE/PostTime/text()') AS NVARCHAR(MAX)) AS DATETIME) , @message_body ) END COMMIT TRANSACTION END END GO -- Active la file d'attente, ce qui lance la réception des événements ALTER QUEUE [dbo].[NotifyBlockingQueue] WITH ACTIVATION ( STATUS = ON, PROCEDURE_NAME = [dbo].[LogBlockingEvents], -- Lance un maximum de 2 instance de la procédure MAX_QUEUE_READERS = 2, -- En tant que l'utilisateur qui a créé la file d'attente EXECUTE AS SELF ) -- Crée la notification IF EXISTS ( SELECT * FROM sys.server_event_notifications WHERE name = 'NotifyLocks' ) DROP EVENT NOTIFICATION NotifyLocks ON SERVER GO CREATE EVENT NOTIFICATION NotifyLocks ON SERVER WITH fan_in FOR blocked_process_report TO SERVICE 'NotifyBlockingService', 'current database' ; GO -- Vue pour examiner les évènements CREATE VIEW dbo.BlockingEvents AS SELECT a.EventTime , EventData.value('(/EVENT_INSTANCE/StartTime)[1]', 'datetime') StartTime , DB_NAME(EventData.value('(/EVENT_INSTANCE/DatabaseID)[1]', 'int')) DBName , Y.x.value('@spid', 'nvarchar(45)') BlockingSpid , X.x.value('@spid', 'nvarchar(45)') BlockedSpid , X.x.value('@id', 'nvarchar(45)') BlockedId , Y.x.value('@hostname', 'nvarchar(45)') BlockingFromHost , Y.x.value('@loginname', 'nvarchar(45)') BlockingFromLogin , Y.x.value('@clientapp', 'nvarchar(100)') BlockingClientApp , Y.x.value('@isolationlevel', 'nvarchar(45)') BlockingFromIso , Y.x.value('data(.)', 'varchar(5000)') AS BlockingSQLcmd , Y.x.value('@waitresource', 'nvarchar(45)') BlockingObject , DB_NAME(X.x.value('@currentdb', 'int')) Blockeddb , X.x.value('@waitresource', 'nvarchar(45)') BlockedObject , X.x.value('@lockMode', 'nvarchar(45)') BlockedBlockLockMode , X.x.value('@hostname', 'nvarchar(45)') BlockedFromHOst , X.x.value('@loginname', 'nvarchar(45)') BlockedFromLogin , X.x.value('@clientapp', 'nvarchar(100)') BlockedClientApp , X.x.value('@isolationlevel', 'nvarchar(45)') BlockedFromIso , X.x.value('data(.)', 'varchar(5000)') AS BlockedSQLcmd FROM dbo.BlockingEventsXML a CROSS APPLY EventData.nodes('EVENT_INSTANCE/TextData/blocked-process-report/blocked-process/process') AS X ( x ) CROSS APPLY EventData.nodes('EVENT_INSTANCE/TextData/blocked-process-report/blocking-process/process') AS Y ( x ) --ORDER BY EventTime desc |
Table of Contents