Par défaut, SQL Server assure le suivi de nombreuses informations précieuses. Depuis SQL Server 2005, une "trace par défaut" est exécutée en arrière-plan et, depuis SQL Server 2008, une session d'événements étendus s'exécute automatiquement, appelée system_health
.
Vous pouvez aussi trouver certaines informations dans le journal des erreurs SQL Server, les journaux d'événements journal, l' agent Windows SQL Server, et l' enregistrement supplémentaire des choses comme SQL Server Audit , Gestion entrepôt de données , les notifications d' événement , Déclencheurs DML , Triggers DDL , SCOM / System Center , vos propres traces côté serveur ou sessions d'événements étendus, ou des solutions de surveillance tierces (comme celles de mon employeur, SQL Sentry ). Vous pouvez également éventuellement activer une "trace Blackbox" pour faciliter le dépannage .
Mais pour cet article, je vais me concentrer sur ce qui est généralement activé presque partout: le suivi par défaut, les sessions d'événements étendus et le journal des erreurs.
Trace par défaut
La trace par défaut s'exécute généralement sur la plupart des systèmes, à moins que vous ne l'ayez désactivée à l'aide desp_configure
. Tant qu'il est activé, cela peut constituer une riche source d'informations précieuses. La liste suivante répertorie les événements de trace capturés:
DECLARE @TraceID INT;
SELECT @TraceID = id FROM sys.traces WHERE is_default = 1;
SELECT t.EventID, e.name as Event_Description
FROM sys.fn_trace_geteventinfo(@TraceID) t
JOIN sys.trace_events e ON t.eventID = e.trace_event_id
GROUP BY t.EventID, e.name;
Vous pouvez entrer plus dans les détails en joignant pour sys.trace_columns
voir quels événements arrivent avec quelles données, mais je vais ignorer cela pour l'instant, car vous pouvez voir ce que vous avez quand vous interrogez les données de trace pour des événements spécifiques. Voici les événements disponibles sur mon système (vous devez exécuter la requête sur le vôtre pour vous assurer qu'ils correspondent, bien qu'il s'agisse toujours du même ensemble d'événements via SQL Server 2019 CTP 2.4):
EventID Event_Description
------- ----------------------------------------------
18 Audit Server Starts And Stops
20 Audit Login Failed
22 ErrorLog
46 Object:Created
47 Object:Deleted
55 Hash Warning
69 Sort Warnings
79 Missing Column Statistics
80 Missing Join Predicate
81 Server Memory Change
92 Data File Auto Grow
93 Log File Auto Grow
94 Data File Auto Shrink
95 Log File Auto Shrink
102 Audit Database Scope GDR Event
103 Audit Schema Object GDR Event
104 Audit Addlogin Event
105 Audit Login GDR Event
106 Audit Login Change Property Event
108 Audit Add Login to Server Role Event
109 Audit Add DB User Event
110 Audit Add Member to DB Role Event
111 Audit Add Role Event
115 Audit Backup/Restore Event
116 Audit DBCC Event
117 Audit Change Audit Event
152 Audit Change Database Owner
153 Audit Schema Object Take Ownership Event
155 FT:Crawl Started
156 FT:Crawl Stopped
164 Object:Altered
167 Database Mirroring State Change
175 Audit Server Alter Trace Event
218 Plan Guide Unsuccessful
Notez que la trace par défaut utilise des fichiers de substitution et que, par conséquent, les données dont vous disposez ne remontent que jusqu'à présent - la plage de dates des données disponibles dépend du nombre d'événements ci-dessus capturés et de leur fréquence. Si vous souhaitez vous assurer de conserver un historique plus long, vous pouvez configurer un travail qui archive périodiquement les fichiers actuellement inactifs associés à la trace.
Exemples
Dans la question, j'ai posé quelques questions que j'ai trouvées. Voici des exemples de requêtes permettant d'extraire ces informations spécifiques de la trace par défaut.
Question: À quand remonte la dernière croissance automatique dans la base de données AdventureWorks et combien de temps a-t-il fallu?
Cette requête extraira tous les événements AutoGrow de la base de données AdventureWorks, pour les fichiers journaux et les fichiers de données, qui figurent toujours dans les fichiers journaux de suivi par défaut:
DECLARE @path NVARCHAR(260);
SELECT
@path = REVERSE(SUBSTRING(REVERSE([path]),
CHARINDEX(CHAR(92), REVERSE([path])), 260)) + N'log.trc'
FROM sys.traces
WHERE is_default = 1;
SELECT
DatabaseName,
[FileName],
SPID,
Duration,
StartTime,
EndTime,
FileType = CASE EventClass WHEN 92 THEN 'Data' ELSE 'Log' END
FROM sys.fn_trace_gettable(@path, DEFAULT)
WHERE EventClass IN (92,93)
AND DatabaseName = N'AdventureWorks'
ORDER BY StartTime DESC;
Question: Qui a supprimé la table dbo.EmployeeAuditData et quand?
Cela renverra tous les DROP
événements pour un objet nommé EmployeeAuditData
. Si vous voulez vous assurer qu'il ne détecte que les DROP
événements des tables, vous pouvez ajouter un filtre: ObjectType = 8277
(la liste complète est documentée ici ). Si vous souhaitez restreindre l'espace de recherche à une base de données spécifique, vous pouvez ajouter un filtre: DatabaseName = N'db_name'
.
DECLARE @path NVARCHAR(260);
SELECT
@path = REVERSE(SUBSTRING(REVERSE([path]),
CHARINDEX(CHAR(92), REVERSE([path])), 260)) + N'log.trc'
FROM sys.traces
WHERE is_default = 1;
SELECT
LoginName,
HostName,
StartTime,
ObjectName,
TextData
FROM sys.fn_trace_gettable(@path, DEFAULT)
WHERE EventClass = 47 -- Object:Deleted
AND EventSubClass = 1
AND ObjectName = N'EmployeeAuditData'
ORDER BY StartTime DESC;
Il ya une complication ici, et c’est un cas très avancé, mais j’ai pensé prudent de mentionner quand même. Si vous utilisez plusieurs schémas et pouvez avoir le même nom d'objet dans plusieurs schémas, vous ne pourrez pas savoir de quel nom il s'agit (à moins que son ou ses homologues existent encore). Il existe un cas externe selon lequel UserA aurait pu supprimer SchemaB.Tablename alors que UserB aurait peut-être supprimé SchemaA.Tablename. La trace par défaut ne suit pas le schéma de l'objet (elle ne capture pas non plus TextData
pour cet événement), et laObjectID
inclus dans la trace n'est pas utile pour une correspondance directe (car l'objet a été supprimé et n'existe plus). Dans ce cas, l'inclusion de cette colonne dans la sortie peut être utile pour établir des références croisées avec les copies de la table portant le même nom qui existent toujours, mais si le système est dans ce désarroi (ou si toutes ces copies ont été supprimées), n’est peut-être toujours pas un moyen fiable de deviner quelle copie de la table a été supprimée par qui.
Événements étendus
A partir de la prise en charge de SQL Server 2008: La session system_health (blog SQLCSS) , voici la liste des données que vous pouvez extraire de la system_health
session dans SQL Server 2008 et 2008 R2:
- Sql_text et session_id pour toutes les sessions rencontrant une erreur avec une gravité> = 20
- Sql_text et session_id pour toutes les sessions rencontrant un type d'erreur "mémoire" tel que 17803, 701, etc. (nous l'avons ajouté car toutes les erreurs mémoire ne sont pas d'une gravité> = 20)
- Un enregistrement de tous les problèmes "non générateurs" (vous les avez parfois vus dans ERRORLOG comme Msg 17883)
- Toute impasse détectée
- Callstack, sql_text et session_id pour toutes les sessions ayant attendu des verrous (ou d'autres ressources intéressantes) pendant plus de 15 secondes
- Callstack, sql_text et session_id pour toutes les sessions ayant attendu des verrous pendant plus de 30 secondes
- Callstack, sql_text et id_session pour toute session ayant attendu pendant une période prolongée des attentes "externes" ou "préventives".
Dans Utiliser la session d'événements system_health (MSDN) , la liste est quelque peu développée dans SQL Server 2012 (et reste la même pour SQL Server 2014):
- Sql_text et session_id pour toutes les sessions rencontrant une erreur de gravité> = 20.
- Sql_text et session_id pour toutes les sessions rencontrant une erreur liée à la mémoire. Les erreurs comprennent 17803, 701, 802, 8645, 8651, 8657 et 8902.
- Un enregistrement de tous les problèmes de planificateur sans rendement. (Celles-ci apparaissent dans le journal des erreurs SQL Server sous la forme d'une erreur 17883.)
- Toute impasse détectée.
- Callstack, sql_text et session_id pour toutes les sessions ayant attendu des verrous (ou d'autres ressources intéressantes) pendant plus de 15 secondes.
- Callstack, sql_text et id_session pour toutes les sessions ayant attendu des verrous pendant plus de 30 secondes.
- Callstack, sql_text et id_session pour toutes les sessions qui ont attendu longtemps pendant des périodes d'attente préemptives. La durée varie selon le type d'attente. Une attente préventive correspond au moment où SQL Server attend des appels d'API externes.
- Callstack et session_id pour l’allocation CLR et les échecs d’allocation virtuelle.
- Les événements ring_buffer pour le courtier en mémoire, le moniteur du planificateur, le MOO de nœud de mémoire, la sécurité et la connectivité.
- Les composants système proviennent de sp_server_diagnostics.
- Intégrité de l'instance collectée par scheduler_monitor_system_health_ring_buffer_recorded.
- Échecs d’allocation CLR.
- Erreurs de connectivité lors de l'utilisation de connectivity_ring_buffer_recorded.
- Erreurs de sécurité lors de l'utilisation de security_error_ring_buffer_recorded.
Dans SQL Server 2016, deux événements supplémentaires sont capturés:
- Lorsqu'un processus est tué à l'aide de la
KILL
commande.
- Lorsque l’arrêt de SQL Server a été démarré.
(La documentation n'a pas encore été mise à jour, mais j'ai blogué sur la façon dont j'ai découvert ces modifications et d'autres .)
Pour obtenir la configuration plus cryptique applicable à votre version spécifique, vous pouvez toujours exécuter la requête suivante directement, mais vous devrez interpréter les noms et analyser les prédicats pour les faire correspondre aux listes de langage plus naturel ci-dessus:
SELECT e.package, e.event_id, e.name, e.predicate
FROM sys.server_event_session_events AS e
INNER JOIN sys.server_event_sessions AS s
ON e.event_session_id = s.event_session_id
WHERE s.name = N'system_health'
ORDER BY e.package, e.name;
Si vous utilisez des groupes de disponibilité, deux nouvelles sessions seront également en cours d'exécution: AlwaysOn_failover
et AlwaysOn_health
. Vous pouvez voir les données qu'ils collectent avec la requête suivante:
SELECT s.name, e.package, e.event_id, e.name, e.predicate
FROM sys.server_event_session_events AS e
INNER JOIN sys.server_event_sessions AS s
ON e.event_session_id = s.event_session_id
WHERE s.name LIKE N'AlwaysOn[_]%'
ORDER BY s.name, e.package, e.name;
Ces sessions d'événements utilisent des cibles de mémoire tampon en anneau pour stocker les données. Ainsi, à l'instar du pool de mémoire tampon et du cache de planification, les événements les plus anciens seront progressivement supprimés. Vous ne pourrez donc pas nécessairement extraire les événements de la plage de dates souhaitée.
Exemple
Dans la question, j'ai posé cette question fictive:
Combien d'erreurs liées à la mémoire se sont produites aujourd'hui?
Voici un exemple (et probablement pas très efficace) de requête pouvant extraire ces informations de la system_health
session:
;WITH src(x) AS
(
SELECT y.query('.')
FROM
(
SELECT x = CONVERT(XML, t.target_data)
FROM sys.dm_xe_sessions AS s
INNER JOIN sys.dm_xe_session_targets AS t
ON s.[address] = t.event_session_address
WHERE s.name = N'system_health'
) AS x
CROSS APPLY x.x.nodes('/RingBufferTarget/event') AS y(y)
)
SELECT
x, ts = CONVERT(DATETIME, NULL), err = CONVERT(INT, NULL)
INTO #blat FROM src;
DELETE #blat WHERE x.value('(/event/@name)[1]', 'varchar(255)') <> 'error_reported';
UPDATE #blat SET ts = x.value('(/event/@timestamp)[1]', 'datetime');
UPDATE #blat SET err = x.value('(/event/data/value)[1]', 'int');
SELECT err, number_of_events = COUNT(*)
FROM #blat
WHERE err IN (17803, 701, 802, 8645, 8651, 8657, 8902)
AND ts >= CONVERT(DATE, CURRENT_TIMESTAMP)
GROUP BY err;
DROP TABLE #blat;
(Cet exemple emprunte vaguement au billet de blog d’introductionsystem_health
d’ Amit Banerjee sur la session .)
Pour plus d'informations sur les événements étendus (y compris de nombreux exemples où vous pouvez interroger des données spécifiques), voir cette série de blogs en 31 parties de Jonathan Kehayias:
https://www.sqlskills.com/blogs/jonathan/an-xevent-a-day-31-days-of-extended-events/
Journal des erreurs
Par défaut, SQL Server conserve les derniers fichiers du journal des erreurs plus les 6 plus récents (mais vous pouvez le modifier ). De nombreuses informations y sont stockées, notamment les informations de démarrage (nombre de cœurs utilisés, définition du verrouillage des pages en mémoire, mode d'authentification, etc.), ainsi que des erreurs et autres scénarios suffisamment graves pour être documentés (et non capturés ailleurs). Un exemple récent était quelqu'un qui cherchait quand une base de données était déconnectée. Vous pouvez le déterminer en parcourant chacun des 7 journaux d'erreurs les plus récents pour le texte Setting database option OFFLINE
:
EXEC sys.sp_readerrorlog 0,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 1,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 2,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 3,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 4,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 5,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 6,1,'Setting database option OFFLINE';
J'ai couvert d'autres détails dans cette réponse récente , et il existe également de bonnes informations de base sur toadworld ainsi que dans la documentation officielle .
Un groupe d '"erreurs" que le journal des erreurs suit par défaut (et peut ralentir considérablement le traitement des informations importantes) est constitué par chaque message de sauvegarde réussi. Vous pouvez empêcher ces derniers de remplir le journal des erreurs avec bruit en activant l'indicateur de trace 3226 .