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_columns
vedere 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 DROP
eventi per un oggetto denominato EmployeeAuditData
. Se vuoi assicurarti che rilevi solo DROP
eventi 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 TextData
per questo evento) e ilObjectID
incluso 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_health
sessione 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
KILL
comando
- 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_failover
e 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_health
sessione:
;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_health
sessione .)
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 .