Há algumas informações valiosas que o SQL Server rastreia para você por padrão. Desde o SQL Server 2005, existe um "rastreamento padrão" executado em segundo plano e, desde o SQL Server 2008, uma sessão de Eventos Estendidos é executada automaticamente, chamada system_health
.
Você também pode encontrar determinadas informações no log de erros do SQL Server, no SQL Server Agent, nos logs de eventos do Windows e nos logs adicionais de coisas como Auditoria do SQL Server , Data Warehouse de Gerenciamento , Notificações de Eventos , Disparadores DML , Disparadores DML , Disparadores DDL , SCOM / System Center , seus próprios rastreamentos do servidor ou sessões de eventos estendidos ou soluções de monitoramento de terceiros (como aquelas feitas pelo meu empregador, o SQL Sentry ). Opcionalmente, você também pode ativar o chamado "rastreamento da caixa preta" para ajudar na solução de problemas .
Mas, para este post, vou focar o escopo nas coisas que geralmente são ativadas em qualquer lugar: o rastreamento padrão, as sessões de eventos estendidos e o log de erros.
Rastreio padrão
O rastreio padrão geralmente está em execução na maioria dos sistemas, a menos que você o tenha desativadosp_configure
. Desde que esteja ativado, isso pode ser uma fonte rica de informações valiosas. A seguir, são listados os eventos de rastreamento capturados:
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;
Você pode entrar em mais detalhes juntando-se a sys.trace_columns
para ver quais eventos vêm com quais dados, mas vou pular isso por enquanto, pois você pode ver o que tem quando consulta os dados de rastreamento para eventos específicos. Estes são os eventos disponíveis no meu sistema (você deve executar a consulta no seu para garantir que eles correspondam, embora este ainda seja o mesmo conjunto de eventos através do 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
Observe que o rastreamento padrão usa arquivos de rollover e, portanto, os dados disponíveis apenas voltarão até agora - o período de dados disponíveis depende de quantos eventos acima estão sendo capturados e com que frequência. Se desejar garantir um histórico mais longo, é possível configurar um trabalho que arquive periodicamente os arquivos inativos atualmente associados ao rastreamento.
Exemplos
Na pergunta, fiz algumas perguntas que encontrei. Aqui estão exemplos de consultas para obter essas informações específicas do rastreamento padrão.
Pergunta: Quando foi a última vez que um crescimento automático ocorreu no banco de dados AdventureWorks e quanto tempo levou?
Essa consulta puxará todos os eventos do AutoGrow no banco de dados AdventureWorks, para arquivos de log e dados, que ainda estão nos arquivos de log de rastreamento padrão:
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;
Pergunta: Quem excluiu a tabela dbo.EmployeeAuditData e quando?
Isso retornará quaisquer DROP
eventos para um objeto chamado EmployeeAuditData
. Se você quiser garantir que ele detecte apenas DROP
eventos para tabelas, adicione um filtro: ObjectType = 8277
(a lista completa está documentada aqui ). Se você quiser restringir o espaço de busca a um banco de dados específico, você pode adicionar um 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;
Há uma complicação aqui, e é um caso muito delicado, mas achei prudente mencionar de qualquer maneira. Se você usar vários esquemas e puder ter o mesmo nome de objeto em vários esquemas, não poderá saber qual é esse (a menos que sua (s) contraparte (s) ainda exista). Há um caso externo de que o UsuárioA possa ter eliminado SchemaB.Tablename, enquanto o UsuárioB possa ter eliminado SchemaA.Tablename. O rastreio padrão não controla o esquema do objeto (nem captura TextData
para este evento) e oObjectID
incluído no rastreamento não é útil para uma correspondência direta (porque o objeto foi descartado e não existe mais). A inclusão dessa coluna na saída, neste caso, pode ser útil para fazer referência cruzada com qualquer cópia da tabela com o mesmo nome que ainda exista, mas se o sistema estiver com tanta confusão (ou se todas essas cópias tiverem sido excluídas) lá ainda pode não ser uma maneira confiável de adivinhar qual cópia da tabela foi descartada por quem.
Eventos estendidos
Do Supporting SQL Server 2008: A sessão system_health (SQLCSS Blog) , a seguir está a lista de dados que você pode selecionar da system_health
sessão no SQL Server 2008 e 2008 R2:
- O sql_text e o session_id para todas as sessões que encontrarem um erro com gravidade> = 20
- O sql_text e o session_id para todas as sessões que encontrarem um tipo de erro de "memória", como 17803, 701, etc. (adicionamos isso porque nem todos os erros de memória têm gravidade> = 20)
- Um registro de problemas "não-produtivos" (algumas vezes você os viu no ERRORLOG como Msg 17883)
- Quaisquer conflitos detectados
- O callstack, sql_text e session_id para todas as sessões que esperaram nas travas (ou outros recursos interessantes) por> 15 segundos
- O callstack, sql_text e session_id para todas as sessões que aguardaram bloqueios por> 30 segundos
- O callstack, sql_text e session_id para qualquer sessão que esperou por um longo período de tempo por esperas "externas" ou "esperas preventivas".
Em Usar a sessão de eventos system_health (MSDN) , a lista é um pouco expandida no SQL Server 2012 (e permanece a mesma para o SQL Server 2014):
- O sql_text e o session_id para todas as sessões que encontrarem um erro com severidade> = 20.
- O sql_text e session_id para todas as sessões que encontrarem um erro relacionado à memória. Os erros incluem 17803, 701, 802, 8645, 8651, 8657 e 8902.
- Um registro de qualquer problema não planejado do planejador. (Eles aparecem no log de erros do SQL Server como erro 17883.)
- Qualquer conflito detectado.
- O callstack, sql_text e session_id para todas as sessões que aguardaram trincas (ou outros recursos interessantes) por> 15 segundos.
- O callstack, sql_text e session_id para todas as sessões que aguardaram bloqueios por> 30 segundos.
- O callstack, sql_text e session_id para todas as sessões que esperaram por um longo tempo por esperas preventivas. A duração varia de acordo com o tipo de espera. Uma espera preventiva é onde o SQL Server está aguardando chamadas de API externas.
- O callstack e o session_id para alocação de CLR e falhas de alocação virtual.
- Os eventos ring_buffer para o intermediário de memória, monitor do planejador, OOM do nó de memória, segurança e conectividade.
- O componente do sistema resulta de sp_server_diagnostics.
- Integridade da instância coletada por scheduler_monitor_system_health_ring_buffer_recorded.
- Falhas na alocação de CLR.
- Erros de conectividade usando connectivity_ring_buffer_recorded.
- Erros de segurança usando security_error_ring_buffer_recorded.
No SQL Server 2016, mais dois eventos são capturados:
- Quando um processo é morto usando o
KILL
comando
- Quando o desligamento do SQL Server foi iniciado.
(A documentação ainda não foi atualizada, mas escrevi em blog sobre como descubro essas e outras alterações .)
Para obter a configuração mais enigmática aplicável à sua versão específica, você sempre pode executar a consulta a seguir diretamente, mas precisará interpretar os nomes e analisar os predicados para corresponder às listas de idiomas mais naturais acima:
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 você estiver usando Grupos de Disponibilidade, também haverá duas novas sessões em execução: AlwaysOn_failover
e AlwaysOn_health
. Você pode ver os dados que eles coletam com a seguinte consulta:
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;
Essas sessões de eventos usam destinos de buffer de anel para armazenar os dados. Assim, como o buffer pool e o cache do plano, os eventos mais antigos serão eliminados gradualmente, para que você não seja capaz de extrair necessariamente eventos do período desejado.
Exemplo
Na pergunta eu fiz esta pergunta fictícia:
Quantos erros relacionados à memória ocorreram hoje?
Aqui está uma amostra (e provavelmente não muito eficiente) de consulta que pode extrair essas informações da system_health
sessão:
;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;
(Este exemplo é emprestado vagamente da postagem introdutória do blogsystem_health
de Amit Banerjee na sessão .)
Para obter mais informações sobre eventos estendidos (incluindo muitos exemplos em que é possível consultar dados específicos), consulte esta série de blogs de 31 partes de Jonathan Kehayias:
https://www.sqlskills.com/blogs/jonathan/an-xevent-a-day-31-days-of-extended-events/
Log de erros
Por padrão, o SQL Server mantém os arquivos de log de erros atuais mais os 6 mais recentes (mas você pode alterar isso ). Muitas informações são armazenadas lá, incluindo informações de inicialização (quantos núcleos estão em uso, se as páginas de bloqueio estão definidas, modo de autenticação etc.), além de erros e outros cenários suficientemente severos para serem documentados (e não capturados em outros lugares). Um exemplo recente foi alguém procurando quando um banco de dados foi colocado offline. Você pode determinar isso examinando cada um dos 7 logs de erro mais recentes do texto 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';
Eu cobri alguns outros detalhes nesta resposta recente , e também há boas informações básicas no toadworld e também na documentação oficial .
Um grupo de "erros" que o log de erros controla por padrão - e pode fazer com que informações importantes caiam muito rapidamente - é toda mensagem de backup bem-sucedida. Você pode impedir que eles preencham o log de erros com ruído ativando o sinalizador de rastreamento 3226 .