¿Qué información de eventos puedo obtener de manera predeterminada de SQL Server?

60

A menudo veo preguntas en las que la gente quiere saber si sucedió algo, o cuándo sucedió, o quién realizó la acción. En muchos casos, SQL Server simplemente no rastrea esta información por sí solo. Por ejemplo:

  • ¿Quién ejecutó por última vez el procedimiento almacenado dbo.MyProcedure?
  • ¿Quién actualizó la salarycolumna en la dbo.Employeestabla?
  • ¿Quién consultó por última vez la dbo.Orderstabla de Management Studio?

Pero hay varios otros eventos de los que SQL Server realiza un seguimiento temporal de forma predeterminada, y pueden responder preguntas de forma nativa, como:

  • ¿Cuándo fue la última vez que ocurrió un crecimiento automático en la base de datos AdventureWorks y cuánto tiempo tardó?
  • ¿Quién borró la dbo.EmployeeAuditDatatabla y cuándo?
  • ¿Cuántos errores relacionados con la memoria han sucedido hoy?

¿Cómo obtengo esta información y cuánto tiempo permanece disponible?

Aaron Bertrand
fuente

Respuestas:

65

Hay bastante información valiosa que SQL Server rastrea para usted de manera predeterminada. Desde SQL Server 2005 ha habido un "seguimiento predeterminado" que se ejecuta en segundo plano, y desde SQL Server 2008 se ha ejecutado automáticamente una sesión de Eventos extendidos, llamada system_health.

También puede encontrar cierta información en el registro de errores de SQL Server, el registro del Agente SQL Server, los registros de eventos de Windows y el registro adicional de cosas como Auditoría de SQL Server , Almacén de datos de administración , Notificaciones de eventos , Disparadores DML , Disparadores DDL , SCOM / System Center , sus propios rastreos del lado del servidor o sesiones de eventos extendidos, o soluciones de monitoreo de terceros (como las realizadas por mi empleador, SQL Sentry ). También puede habilitar opcionalmente el llamado "seguimiento de Blackbox" para ayudar en la resolución de problemas .

Pero para esta publicación, voy a centrar el alcance en cosas que generalmente están habilitadas en casi todas partes: el seguimiento predeterminado, las sesiones de eventos extendidos y el registro de errores.

Rastreo predeterminado

El rastreo predeterminado generalmente se ejecuta en la mayoría de los sistemas, a menos que lo haya deshabilitado usandosp_configure . Mientras esté habilitado, esta puede ser una rica fuente de información valiosa. A continuación se enumeran los eventos de rastreo que se capturan:

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;

Puede obtener más detalles uniéndose a sys.trace_columnspara ver qué eventos vienen con qué datos, pero voy a omitir eso por ahora, ya que puede ver lo que tiene cuando consulta los datos de rastreo para eventos específicos. Estos son los eventos que están disponibles en mi sistema (debe ejecutar la consulta en el suyo para asegurarse de que coincidan, aunque este sigue siendo el mismo conjunto de eventos a través de 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

Tenga en cuenta que la traza predeterminada utiliza archivos de sustitución y, por lo tanto, los datos disponibles para usted solo se remontarán hasta ahora: el rango de fechas de los datos disponibles depende de cuántos de los eventos anteriores se capturan y con qué frecuencia. Si desea asegurarse de mantener un historial más largo, puede configurar un trabajo que archiva periódicamente los archivos actualmente inactivos asociados con la traza.

Ejemplos

En la pregunta hice un par de preguntas que he encontrado. Aquí hay ejemplos de consultas para extraer esa información específica de la traza predeterminada.

Pregunta: ¿Cuándo fue la última vez que ocurrió un crecimiento automático en la base de datos AdventureWorks y cuánto tiempo tardó?

Esta consulta extraerá todos los eventos de AutoGrow en la base de datos AdventureWorks, tanto para archivos de registro como de datos, que todavía están en los archivos de registro de rastreo predeterminados:

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;

Pregunta: ¿Quién eliminó la tabla dbo.EmployeeAuditData y cuándo?

Esto devolverá cualquier DROPevento para un objeto llamado EmployeeAuditData. Si desea asegurarse de que solo detecte DROPeventos para tablas, puede agregar un filtro: ObjectType = 8277(la lista completa se documenta aquí ). Si desea restringir el espacio de búsqueda a una base de datos específica, se puede añadir 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;

Aquí hay una complicación, y es un caso muy marginal, pero pensé que era prudente mencionarlo de todos modos. Si usa múltiples esquemas y puede tener el mismo nombre de objeto en múltiples esquemas, no podrá saber cuál es (a menos que su contraparte todavía exista). Existe un caso externo en el que UserA podría haber eliminado SchemaB.Tablename mientras que UserB podría haber eliminado SchemaA.Tablename. La traza predeterminada no rastrea el esquema del objeto (ni captura TextDatapara este evento), y elObjectIDincluido en el seguimiento no es útil para una coincidencia directa (porque el objeto se descartó y ya no existe). Incluir esa columna en la salida en este caso podría ser útil para hacer una referencia cruzada con cualquier copia de la tabla con el mismo nombre que todavía existe, pero si el sistema está en este desorden (o si se han eliminado todas esas copias) Todavía podría no ser una forma confiable de adivinar qué copia de la tabla se dejó caer por quién.

Eventos extendidos

Desde Supporting SQL Server 2008: la sesión system_health (SQLCSS Blog) , la siguiente es la lista de datos que puede eliminar de la system_healthsesión en SQL Server 2008 y 2008 R2:

  • El sql_text y session_id para cualquier sesión que encuentre un error con severidad> = 20
  • Sql_text y session_id para cualquier sesión que encuentre un tipo de error de "memoria" como 17803, 701, etc. (agregamos esto porque no todos los errores de memoria son severidad> = 20)
  • Un registro de cualquier problema "no productivo" (a veces los ha visto en el ERRORLOG como Msg 17883)
  • Cualquier punto muerto que se detecte
  • Callstack, sql_text y session_id para cualquier sesión que haya esperado en pestillos (u otros recursos interesantes) durante> 15 segundos
  • Callstack, sql_text y session_id para cualquier sesión que haya esperado en bloqueos durante> 30 segundos
  • El callstack, sql_text y session_id para cualquier sesión que haya esperado durante un período prolongado de espera "externa" o "espera preventiva".

Desde Usar la sesión del evento system_health (MSDN) , la lista se expande en SQL Server 2012 (y sigue siendo la misma para SQL Server 2014):

  • Sql_text y session_id para cualquier sesión que encuentre un error que tenga una gravedad> = 20.
  • Sql_text y session_id para cualquier sesión que encuentre un error relacionado con la memoria. Los errores incluyen 17803, 701, 802, 8645, 8651, 8657 y 8902.
  • Un registro de cualquier problema del planificador no productivo. (Estos aparecen en el registro de errores de SQL Server como error 17883.)
  • Cualquier punto muerto que se detecte.
  • Callstack, sql_text y session_id para cualquier sesión que haya esperado en pestillos (u otros recursos interesantes) durante> 15 segundos.
  • Callstack, sql_text y session_id para cualquier sesión que haya esperado en bloqueos durante> 30 segundos.
  • Callstack, sql_text y session_id para cualquier sesión que haya esperado durante mucho tiempo las esperas preventivas. La duración varía según el tipo de espera. Una espera preventiva es donde SQL Server está esperando llamadas API externas.
  • Callstack y session_id para la asignación de CLR y fallas de asignación virtual.
  • Los eventos ring_buffer para el intermediario de memoria, el monitor del planificador, el nodo de memoria OOM, la seguridad y la conectividad.
  • Resultados del componente del sistema de sp_server_diagnostics.
  • Estado de la instancia recopilada por Scheduler_monitor_system_health_ring_buffer_recorded.
  • Fallos de asignación de CLR.
  • Errores de conectividad al utilizar connect_ring_buffer_recorded.
  • Errores de seguridad al usar security_error_ring_buffer_recorded.

En SQL Server 2016, se capturan dos eventos más:

  • Cuando se mata un proceso usando el KILLcomando.
  • Cuando se inicia el apagado de SQL Server.

(La documentación aún no se ha actualizado, pero escribí en un blog sobre cómo descubro estos y otros cambios ).

Para obtener la configuración más críptica aplicable a su versión específica, siempre puede ejecutar la siguiente consulta directamente, pero tendrá que interpretar los nombres y analizar los predicados para que coincidan con las listas de lenguaje más naturales anteriores:

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 está utilizando Grupos de disponibilidad, también hay dos nuevas sesiones que encontrará ejecutándose: AlwaysOn_failovery AlwaysOn_health. Puede ver los datos que recopilan con la siguiente 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;

Estas sesiones de eventos usan destinos de búfer en anillo para almacenar los datos, por lo que, al igual que el grupo de búferes y el caché del plan, los eventos más antiguos se eliminarán gradualmente, por lo que no necesariamente podrá extraer eventos del rango de fechas que desee.

Ejemplo

En la pregunta que planteé esta pregunta ficticia:

¿Cuántos errores relacionados con la memoria han sucedido hoy?

Aquí hay una consulta de muestra (y probablemente no muy eficiente) que puede extraer esta información de la system_healthsesión:

;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 ejemplo se toma libremente de la publicación de blog introductoriasystem_health de Amit Banerjee sobre la sesión ).

Para obtener más información sobre eventos extendidos (incluidos muchos ejemplos donde puede consultar datos específicos), consulte esta serie de blogs de 31 partes de Jonathan Kehayias:

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

Registro de errores

SQL Server mantiene de forma predeterminada los archivos de registro de errores actuales más los 6 más recientes (pero puede cambiar esto ). Allí se almacena mucha información, incluida la información de inicio (cuántos núcleos están en uso, si se configuran las páginas bloqueadas en la memoria, el modo de autenticación, etc.), así como los errores y otros escenarios lo suficientemente graves como para documentarse (y no capturarse en otro lugar). Un ejemplo reciente fue alguien que buscaba cuando una base de datos se desconectaba. Puede determinar esto escaneando cada uno de los 7 registros de errores más recientes para el 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';

Cubrí algunos otros detalles en esta respuesta reciente , y también hay buena información de antecedentes en toadworld y también en la documentación oficial .

Un grupo de "errores" que el registro de errores rastrea por defecto, y puede hacer que la información importante se caiga mucho más rápido, es cada mensaje de respaldo exitoso. Puede evitar que estos llenen el registro de errores con ruido activando el indicador de seguimiento 3226 .

Aaron Bertrand
fuente