Accueil / Articles / Définir une trace XEvents : exemples de filtres
› ArticleDéfinir une trace XEvents dans SQL Server : méthode et exemples de filtres.
Les événements étendus (XEvents) ont remplacé SQL Profiler : plus légers, plus précis, et exploitables en production. Voici comment construire une session, puis des exemples de filtres sur une table, une base, une opération ou une application.
Les quatre briques d'une session
Une session d'événements étendus se compose de quatre éléments, déclarés dans une seule commande CREATE EVENT SESSION :
- Les événements : ce que l'on veut observer (fin d'une requête, erreur, interblocage, extension de fichier).
- Les prédicats : le filtre appliqué à chaque événement (
WHERE). Il est évalué en premier, avant toute collecte : c'est lui qui limite l'impact sur le serveur. - Les actions : les informations supplémentaires attachées à l'événement (nom de la base, application, login, texte de la requête).
- Les cibles : où l'on enregistre. Le plus courant est un fichier
.xel(package0.event_file) ; la mémoire tampon circulaire (ring_buffer) convient aux observations brèves.
Le droit nécessaire est ALTER ANY EVENT SESSION (ou CONTROL SERVER à partir de SQL Server 2022 selon la nomenclature des droits). Pour explorer les événements disponibles : SELECT name FROM sys.dm_xe_objects WHERE object_type = 'event'.
Exemple 1 : les requêtes lentes d'une base
C'est la session de base : toute requête ou procédure de la base MaBase qui dure plus d'une seconde. La durée est exprimée en microsecondes dans les événements : une seconde vaut 1 000 000.
CREATE EVENT SESSION [ADOC_requetes_lentes] ON SERVER
ADD EVENT sqlserver.sql_statement_completed
(
ACTION (sqlserver.database_name, sqlserver.client_app_name, sqlserver.client_hostname,
sqlserver.username, sqlserver.session_id, sqlserver.sql_text)
WHERE (sqlserver.database_name = N'MaBase' AND duration > 1000000)
),
ADD EVENT sqlserver.rpc_completed
(
ACTION (sqlserver.database_name, sqlserver.client_app_name, sqlserver.client_hostname,
sqlserver.username, sqlserver.session_id, sqlserver.sql_text)
WHERE (sqlserver.database_name = N'MaBase' AND duration > 1000000)
)
ADD TARGET package0.event_file
(
SET filename = N'D:\XE\ADOC_requetes_lentes.xel', -- le dossier doit exister
max_file_size = 100, -- Mo par fichier
max_rollover_files = 5 -- 5 fichiers tournants au maximum
)
WITH (MAX_MEMORY = 4096 KB,
EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS,
MAX_DISPATCH_LATENCY = 30 SECONDS,
STARTUP_STATE = OFF);La session est créée à l'arrêt. On la démarre, puis on l'arrête dès l'observation terminée :
ALTER EVENT SESSION [ADOC_requetes_lentes] ON SERVER STATE = START;
-- ... laisser tourner pendant la période à observer ...
ALTER EVENT SESSION [ADOC_requetes_lentes] ON SERVER STATE = STOP;Exemple 2 : les opérations sur une table
Les événements de fin de requête ne portent pas directement le nom de la table. Le moyen le plus simple consiste à filtrer sur le texte de l'instruction avec like_i_sql_unicode_string (insensible à la casse).
CREATE EVENT SESSION [ADOC_table_commandes] ON SERVER
ADD EVENT sqlserver.sql_statement_completed
(
ACTION (sqlserver.database_name, sqlserver.client_app_name, sqlserver.username,
sqlserver.session_id, sqlserver.sql_text)
WHERE (sqlserver.database_name = N'MaBase'
AND sqlserver.like_i_sql_unicode_string(statement, N'%Commandes%'))
),
ADD EVENT sqlserver.sp_statement_completed -- instructions exécutées dans les procédures
(
ACTION (sqlserver.database_name, sqlserver.client_app_name, sqlserver.username,
sqlserver.session_id)
WHERE (sqlserver.database_name = N'MaBase'
AND sqlserver.like_i_sql_unicode_string(statement, N'%Commandes%'))
)
ADD TARGET package0.event_file (SET filename = N'D:\XE\ADOC_table_commandes.xel', max_file_size = 100, max_rollover_files = 5)
WITH (STARTUP_STATE = OFF);- Le filtre texte attrape aussi les colonnes ou les objets dont le nom contient « Commandes » : resserrez le motif (
%dbo.Commandes%) si besoin. - Une table accédée uniquement par une vue ou une procédure n'apparaît pas dans le texte de l'appelant. L'événement
sp_statement_completedaide, puisqu'il voit les instructions internes des procédures. - Pour tracer qui modifie la structure d'une table (colonnes, index), voir plutôt l'exemple 4 sur les opérations DDL.
- Ce type de filtre texte est plus coûteux qu'un filtre sur un nombre : associez-le toujours à une base, et ajoutez au besoin un seuil de durée.
Exemple 3 : toute l'activité d'une base
Pour une observation large, filtrez sur la base par son identifiant, plus rapide à comparer que son nom. Trouvez l'identifiant avec SELECT DB_ID(N'MaBase'), ici supposé égal à 7.
CREATE EVENT SESSION [ADOC_base_complete] ON SERVER
ADD EVENT sqlserver.sql_batch_completed
(
ACTION (sqlserver.client_app_name, sqlserver.username, sqlserver.session_id, sqlserver.sql_text)
WHERE (sqlserver.database_id = 7)
),
ADD EVENT sqlserver.rpc_completed
(
ACTION (sqlserver.client_app_name, sqlserver.username, sqlserver.session_id, sqlserver.sql_text)
WHERE (sqlserver.database_id = 7)
)
ADD TARGET package0.event_file (SET filename = N'D:\XE\ADOC_base_complete.xel', max_file_size = 200, max_rollover_files = 3)
WITH (STARTUP_STATE = OFF);Sur une base très active, cette session produit beaucoup de volume. Limitez-la dans le temps, ou ajoutez un prédicat de durée ou de nombre de lignes : row_count > 10000, par exemple, pour repérer les requêtes qui renvoient des volumes anormaux.
Exemple 4 : une opération particulière
Selon le besoin, on choisit l'événement qui correspond à l'opération. Trois cas fréquents.
Les modifications de structure (DDL). Qui crée, modifie ou supprime des objets dans la base ?
CREATE EVENT SESSION [ADOC_ddl] ON SERVER
ADD EVENT sqlserver.object_created (ACTION (sqlserver.database_name, sqlserver.username, sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.sql_text)
WHERE (sqlserver.database_name = N'MaBase')),
ADD EVENT sqlserver.object_altered (ACTION (sqlserver.database_name, sqlserver.username, sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.sql_text)
WHERE (sqlserver.database_name = N'MaBase')),
ADD EVENT sqlserver.object_deleted (ACTION (sqlserver.database_name, sqlserver.username, sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.sql_text)
WHERE (sqlserver.database_name = N'MaBase'))
ADD TARGET package0.event_file (SET filename = N'D:\XE\ADOC_ddl.xel', max_file_size = 50, max_rollover_files = 5)
WITH (STARTUP_STATE = OFF);Une même opération peut apparaître deux fois (début et fin de phase DDL) : filtrez à la lecture.
Les erreurs. Les erreurs de gravité 16 et plus (hors messages informatifs), toutes bases confondues :
CREATE EVENT SESSION [ADOC_erreurs] ON SERVER
ADD EVENT sqlserver.error_reported
(
ACTION (sqlserver.database_name, sqlserver.client_app_name, sqlserver.username, sqlserver.sql_text)
WHERE (severity >= 16)
)
ADD TARGET package0.event_file (SET filename = N'D:\XE\ADOC_erreurs.xel', max_file_size = 50, max_rollover_files = 5)
WITH (STARTUP_STATE = OFF);Pour cibler une erreur précise, par exemple les échecs de connexion (18456), remplacez le prédicat par error_number = 18456.
Les blocages prolongés. L'événement blocked_process_report ne se déclenche qu'après activation d'un seuil, en secondes :
EXEC sys.sp_configure N'show advanced options', 1; RECONFIGURE;
EXEC sys.sp_configure N'blocked process threshold (s)', 20; RECONFIGURE; -- rapport après 20 s de blocage
CREATE EVENT SESSION [ADOC_blocages] ON SERVER
ADD EVENT sqlserver.blocked_process_report
ADD TARGET package0.event_file (SET filename = N'D:\XE\ADOC_blocages.xel', max_file_size = 50, max_rollover_files = 5)
WITH (STARTUP_STATE = OFF);Exemple 5 : une application ou un utilisateur
Pour savoir ce que fait un outil ou un compte précis (un ETL, un progiciel, un compte de service), le filtre porte sur le nom d'application ou le login. Ces deux informations sont des prédicats comme les autres.
CREATE EVENT SESSION [ADOC_application] ON SERVER
ADD EVENT sqlserver.sql_batch_completed
(
ACTION (sqlserver.database_name, sqlserver.client_hostname, sqlserver.session_id, sqlserver.sql_text)
WHERE (sqlserver.client_app_name = N'MonProgiciel'
-- ou : sqlserver.username = N'DOMAINE\svc_etl'
AND duration > 100000) -- 100 ms
)
ADD TARGET package0.event_file (SET filename = N'D:\XE\ADOC_application.xel', max_file_size = 100, max_rollover_files = 5)
WITH (STARTUP_STATE = OFF);Le nom d'application est déclaré par l'appelant dans la chaîne de connexion (Application Name=). Si l'application ne le renseigne pas, utilisez le nom du poste (sqlserver.client_hostname).
Les interblocages sont déjà enregistrés
Inutile de créer une session pour les deadlocks : la session system_health, active par défaut, enregistre le rapport de chaque interblocage. On le lit ainsi :
SELECT
x.evt.value('(@timestamp)[1]', 'datetime2') AS date_utc,
CAST(x.evt.query('(data[@name="xml_report"]/value/deadlock)[1]') AS xml) AS rapport_deadlock
FROM (
SELECT CAST(event_data AS xml) AS e
FROM sys.fn_xe_file_target_read_file(N'system_health*.xel', NULL, NULL, NULL)
WHERE object_name = N'xml_deadlock_report'
) AS t
CROSS APPLY t.e.nodes('/event') AS x(evt)
ORDER BY date_utc DESC;Le rapport XML s'ouvre dans SSMS sous forme de graphe, ce qui montre les deux transactions, les verrous détenus et les verrous attendus. Selon l'instance, indiquez le chemin complet du fichier si le nom relatif n'est pas trouvé : les fichiers sont dans le dossier des journaux d'erreurs (LOG).
Lire les fichiers .xel
Les événements sont enregistrés au format XML. La fonction sys.fn_xe_file_target_read_file les expose ligne à ligne ; on en extrait les colonnes avec value().
SELECT
x.evt.value('(@timestamp)[1]', 'datetime2') AS date_utc,
x.evt.value('(@name)[1]', 'nvarchar(60)') AS evenement,
x.evt.value('(data[@name="duration"]/value)[1]', 'bigint') / 1000.0 AS duree_ms,
x.evt.value('(data[@name="cpu_time"]/value)[1]', 'bigint') / 1000.0 AS cpu_ms,
x.evt.value('(data[@name="logical_reads"]/value)[1]', 'bigint') AS lectures_logiques,
x.evt.value('(data[@name="row_count"]/value)[1]', 'bigint') AS lignes,
x.evt.value('(action[@name="database_name"]/value)[1]', 'nvarchar(128)') AS base,
x.evt.value('(action[@name="client_app_name"]/value)[1]', 'nvarchar(256)') AS application,
x.evt.value('(action[@name="username"]/value)[1]', 'nvarchar(256)') AS utilisateur,
x.evt.value('(action[@name="sql_text"]/value)[1]', 'nvarchar(max)') AS requete
FROM (
SELECT CAST(event_data AS xml) AS e
FROM sys.fn_xe_file_target_read_file(N'D:\XE\ADOC_requetes_lentes*.xel', NULL, NULL, NULL)
) AS t
CROSS APPLY t.e.nodes('/event') AS x(evt)
ORDER BY duree_ms DESC;- Les heures sont en UTC. Pour l'heure locale :
date_utc AT TIME ZONE 'UTC' AT TIME ZONE 'Romance Standard Time'(SQL Server 2016 et suivants). - Le joker
*dans le nom lit tous les fichiers tournants d'un coup. - Pour une analyse lourde, copiez d'abord le résultat dans une table temporaire : l'extraction XML est coûteuse, mieux vaut ne la faire qu'une fois.
- SSMS propose aussi une lecture graphique : Gestion, Événements étendus, Sessions, clic droit sur la session, puis « Voir les données cibles ».
Gérer ses sessions
-- Sessions définies, et sessions démarrées
SELECT s.name, s.startup_state,
CASE WHEN r.name IS NULL THEN 'arrêtée' ELSE 'démarrée' END AS etat
FROM sys.server_event_sessions AS s
LEFT JOIN sys.dm_xe_sessions AS r ON r.name = s.name;
-- Arrêter, puis supprimer une session
ALTER EVENT SESSION [ADOC_requetes_lentes] ON SERVER STATE = STOP;
DROP EVENT SESSION [ADOC_requetes_lentes] ON SERVER;Supprimer la session n'efface pas les fichiers .xel : pensez à les archiver ou à les supprimer vous-même.
Limiter l'impact sur la production
- Filtrez le plus tôt possible. Un prédicat sur la base et sur la durée évite d'enregistrer des millions d'événements inutiles.
- Évitez les événements très verbeux comme
lock_acquiredousp_statement_startingsans filtre très étroit. - Bornez le stockage avec
max_file_sizeetmax_rollover_files, sur un disque qui n'est pas celui des données ni du journal. - Démarrez et arrêtez à la demande (
STARTUP_STATE = OFF), sauf pour les sessions de surveillance permanentes. - Testez le volume sur quelques minutes avant une longue collecte.
À retenir
- Une session XEvents se définit par ses événements, ses prédicats, ses actions et ses cibles ; le filtre (WHERE) est la clé de la légèreté.
- Les durées sont en microsecondes et les heures en UTC dans les fichiers .xel.
- Pour une table, filtrez sur le texte de l'instruction ; pour une base, sur son identifiant ; pour une application, sur son nom ; pour les deadlocks, lisez system_health.
- Limitez le volume (taille de fichier, rotation, durée) et arrêtez la session quand l'observation est terminée.
Expertises liées.
Un incident, un audit, une question ?
Un premier échange suffit à cadrer l'urgence et le périmètre.