Quali informazioni sugli eventi posso ottenere per impostazione predefinita da SQL Server?


60

Vedo spesso domande in cui le persone vogliono sapere se è accaduta una certa cosa, o quando è successo o chi ha eseguito l'azione. In molti casi, SQL Server non tiene traccia di queste informazioni da solo. Per esempio:

  • Chi ha eseguito l'ultima stored procedure dbo.MyProcedure?
  • Chi ha aggiornato la salarycolonna nella dbo.Employeestabella?
  • Chi ha eseguito l'ultima query sul dbo.Orderstavolo da Management Studio?

Ma ci sono molti altri eventi che SQL Server tiene traccia temporaneamente per impostazione predefinita e possono rispondere in modo nativo a domande su, come ad esempio:

  • Quando è stata l'ultima volta in cui si è verificata una crescita automatica nel database AdventureWorks e quanto tempo ci è voluto?
  • Chi ha eliminato la dbo.EmployeeAuditDatatabella e quando?
  • Quanti errori relativi alla memoria sono accaduti oggi?

Come ottengo queste informazioni e per quanto tempo rimangono disponibili?

Risposte:


65

Ci sono molte informazioni preziose che SQL Server traccia per te per impostazione predefinita. Da SQL Server 2005 è stata eseguita una "traccia predefinita" in background e da SQL Server 2008 è stata eseguita automaticamente una sessione di eventi estesi, chiamata system_health.

È inoltre possibile trovare alcune informazioni dal registro degli errori di SQL Server, dal registro degli agenti di SQL Server, dai registri degli eventi di Windows e dalla registrazione aggiuntiva di elementi quali audit di SQL Server , gestione dei dati di gestione , notifiche di eventi , trigger DML , trigger DDL , SCOM / System Center , le tue tracce lato server o sessioni di eventi estesi o soluzioni di monitoraggio di terze parti (come quelle create dal mio datore di lavoro, SQL Sentry ). È inoltre possibile abilitare facoltativamente una cosiddetta "traccia Blackbox" per facilitare la risoluzione dei problemi .

Ma per questo post focalizzerò l'ambito su cose che sono generalmente abilitate ovunque: la traccia predefinita, le sessioni degli eventi estesi e il registro degli errori.

Traccia predefinita

La traccia predefinita di solito è in esecuzione sulla maggior parte dei sistemi, a meno che non sia stata disabilitata tramitesp_configure . Finché è abilitato, questa può essere una ricca fonte di informazioni preziose. Di seguito sono elencati gli eventi di traccia acquisiti:

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;

Puoi ottenere maggiori dettagli unendoti a sys.trace_columnsvedere quali eventi provengono da quali dati, ma per ora lo salterò, poiché puoi vedere cosa hai quando esegui effettivamente la query dei dati di traccia per eventi specifici. Questi sono gli eventi disponibili sul mio sistema (dovresti eseguire la tua query per assicurarti che corrispondano, anche se questo è sempre lo stesso set di eventi tramite CTP 2.4 di SQL Server 2019):

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

Si noti che la traccia predefinita utilizza i file di rollover e quindi i dati disponibili torneranno indietro fino a quel momento - l'intervallo di date dei dati disponibili dipende da quanti degli eventi sopra vengono acquisiti e con quale frequenza. Se si desidera assicurarsi di mantenere una cronologia più lunga, è possibile impostare un processo che archivia periodicamente i file attualmente inattivi associati alla traccia.

Esempi

Nella domanda ho posto un paio di domande che ho trovato. Ecco alcune query di esempio per estrarre tali informazioni specifiche dalla traccia predefinita.

Domanda: quando è stata l'ultima volta in cui si è verificata una crescita automatica nel database AdventureWorks e quanto tempo ci è voluto?

Questa query estrarrà tutti gli eventi AutoGrow nel database AdventureWorks, sia per i file di registro che per quelli di dati, che sono ancora nei file di registro di traccia predefiniti:

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;

Domanda: chi ha eliminato la tabella dbo.EmployeeAuditData e quando?

Ciò restituirà tutti gli DROPeventi per un oggetto denominato EmployeeAuditData. Se vuoi assicurarti che rilevi solo DROPeventi per le tabelle, puoi aggiungere un filtro: ObjectType = 8277(l' elenco completo è documentato qui ). Se si desidera limitare lo spazio di ricerca in un database specifico, è possibile aggiungere un filtro: 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;

C'è una complicazione qui, ed è un caso molto marginale ma ho pensato che fosse prudente menzionarlo comunque. Se si utilizzano più schemi e si può avere lo stesso nome oggetto in più schemi, non si sarà in grado di dire quale sia (a meno che non ne esistano ancora le controparti). Esiste un caso esterno in cui UserA potrebbe aver eliminato SchemaB.Tablename mentre UserB potrebbe aver eliminato SchemaA.Tablename. La traccia predefinita non tiene traccia dello schema dell'oggetto (né cattura TextDataper questo evento) e ilObjectIDincluso nella traccia non è utile per una corrispondenza diretta (poiché l'oggetto è stato eliminato e non esiste più). Includere quella colonna nell'output in questo caso potrebbe essere utile per fare un riferimento incrociato con qualsiasi copia della tabella con lo stesso nome che esiste ancora, ma se il sistema è così disordinato (o se tutte queste copie sono state cancellate) lì potrebbe ancora non essere un modo affidabile per indovinare a quale copia del tavolo è stata rilasciata da chi.

Eventi estesi

Dal supporto di SQL Server 2008: la sessione system_health (blog SQLCSS) , di seguito è riportato un elenco di dati che è possibile selezionare dalla system_healthsessione in SQL Server 2008 e 2008 R2:

  • Sql_text e session_id per tutte le sessioni che riscontrano un errore con gravità> = 20
  • Sql_text e session_id per tutte le sessioni che riscontrano un tipo di errore "memoria" come 17803, 701, ecc. (L'abbiamo aggiunto perché non tutti gli errori di memoria sono di gravità> = 20)
  • Una registrazione di eventuali problemi "non produttivi" (a volte li avete visti su ERRORLOG come Msg 17883)
  • Eventuali deadlock rilevati
  • Callstack, sql_text e session_id per tutte le sessioni che hanno atteso sui latch (o altre risorse interessanti) per> 15 secondi
  • Callstack, sql_text e session_id per tutte le sessioni che hanno atteso sui blocchi per> 30 secondi
  • Callstack, sql_text e session_id per tutte le sessioni che hanno atteso per un periodo di tempo prolungato attese "esterne" o "attese preventive".

Da Usa la sessione dell'evento system_health (MSDN) , l'elenco è in qualche modo espanso in SQL Server 2012 (e rimane lo stesso per SQL Server 2014):

  • Sql_text e session_id per tutte le sessioni che riscontrano un errore con gravità> = 20.
  • Sql_text e session_id per tutte le sessioni che riscontrano un errore relativo alla memoria. Gli errori includono 17803, 701, 802, 8645, 8651, 8657 e 8902.
  • Un record di eventuali problemi di scheduler senza cedimenti. (Questi vengono visualizzati nel log degli errori di SQL Server come errore 17883.)
  • Eventuali deadlock rilevati.
  • Callstack, sql_text e session_id per tutte le sessioni che hanno atteso sui latch (o altre risorse interessanti) per> 15 secondi.
  • Callstack, sql_text e session_id per tutte le sessioni che hanno atteso sui blocchi per> 30 secondi.
  • Callstack, sql_text e session_id per tutte le sessioni che hanno atteso a lungo per attese preventive. La durata varia in base al tipo di attesa. Un'attesa preventiva è dove SQL Server è in attesa di chiamate API esterne.
  • Callstack e session_id per allocazione CLR e errori di allocazione virtuale.
  • Gli eventi ring_buffer per broker di memoria, monitor dello scheduler, OOM del nodo di memoria, sicurezza e connettività.
  • Risultati dei componenti di sistema da sp_server_diagnostics.
  • Integrità dell'istanza raccolta da scheduler_monitor_system_health_ring_buffer_recorded.
  • Errori di allocazione CLR.
  • Errori di connettività utilizzando connectivity_ring_buffer_recorded.
  • Errori di sicurezza con security_error_ring_buffer_recorded.

In SQL Server 2016 vengono acquisiti altri due eventi:

  • Quando un processo viene interrotto usando il KILLcomando
  • Quando è stato avviato l'arresto di SQL Server.

(La documentazione non è stata ancora aggiornata, ma ho scritto un blog su come scopro queste e altre modifiche .)

Per ottenere la configurazione più criptica applicabile per la tua versione specifica, puoi sempre eseguire direttamente la seguente query, ma dovrai interpretare i nomi e analizzare i predicati per abbinare gli elenchi di linguaggio più naturali sopra:

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;

Se stai utilizzando i gruppi di disponibilità, ci sono anche due nuove sessioni che troverai in esecuzione: AlwaysOn_failovere AlwaysOn_health. Puoi vedere i dati raccolti con la seguente query:

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;

Queste sessioni di eventi utilizzano target buffer ad anello per archiviare i dati, quindi - come il pool di buffer e la cache del piano - gli eventi più vecchi verranno eliminati gradualmente, quindi non sarà necessariamente possibile estrarre gli eventi dall'intervallo di date desiderato.

Esempio

Nella domanda ho posto questa domanda fittizia:

Quanti errori relativi alla memoria sono accaduti oggi?

Ecco una query di esempio (e probabilmente non molto efficiente) che può estrarre queste informazioni dalla system_healthsessione:

;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;

(Questo esempio prende in prestito vagamente dal post di blog introduttivo di Amit Banerjee sulla system_healthsessione .)

Per ulteriori informazioni sugli eventi estesi (inclusi molti esempi in cui è possibile eseguire query per dati specifici), vedere questa serie di blog in 31 parti di Jonathan Kehayias:

https://www.sqlskills.com/blogs/jonathan/an-xevent-a-day-31-days-of-extended-events/

Registro errori

SQL Server per impostazione predefinita mantiene i più attuali 6 file di registro degli errori più recenti (ma è possibile modificarlo ). Un sacco di informazioni sono memorizzate lì, comprese le informazioni di avvio (quanti core sono in uso, se sono impostate le pagine di blocco in memoria, la modalità di autenticazione, ecc.) Così come errori e altri scenari abbastanza gravi da essere documentati (e non catturati altrove). Un esempio recente è stato qualcuno che cercava quando un database veniva portato offline. È possibile determinare ciò eseguendo la scansione di ciascuno dei 7 registri errori più recenti per il testo 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';

Ho coperto altri dettagli in questa recente risposta , e ci sono anche alcune buone informazioni di base su Toadworld e anche nella documentazione ufficiale .

Un gruppo di "errori" che il registro errori tiene traccia per impostazione predefinita - e può far sì che le informazioni importanti cadano molto più rapidamente dalla coda - è ogni messaggio di backup riuscito. È possibile impedire che questi riempiano il registro degli errori con il rumore abilitando il flag di traccia 3226 .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.