sql >> Base de Datos >  >> RDS >> Database

Eliminación de la traza predeterminada:parte 3

[ Parte 1 | Parte 2 | Parte 3 ]

En la parte 1 de esta serie, expliqué cómo llegué a la conclusión de que deberíamos desactivar el seguimiento predeterminado. En la parte 2, mostré la sesión de eventos extendidos que implementé para capturar todos los eventos de cambio de tamaño de archivo. En esta publicación, quiero mostrar las vistas que creé para facilitar el consumo de los datos de eventos para las personas, y también para explicar algunas advertencias.

Vistas digeribles

Primero, creé una vista que expondría los bits importantes de los datos de la sesión de eventos extendidos y la puse en la base de datos de utilidades que existe en cada instancia:

CREATE VIEW dbo.vwFileSizeChanges
AS
  WITH FileInfo(XEPath) AS
  (
    SELECT LEFT(BasePath,COALESCE(NULLIF(CHARINDEX(SessName,BasePath)-1,-1),0)) + SessName + N'*.xel' 
    FROM
    (
      SELECT xmlsrc.data.value(N'(@name)[1]', N'nvarchar(max)'), SessName
      FROM 
      (
        SELECT CONVERT(xml,target_data), s.[name]
          FROM sys.dm_xe_session_targets AS t
          INNER JOIN sys.dm_xe_sessions AS s
          ON s.[address] = t.event_session_address
          WHERE s.[name] = N'FileSizeChanges'
      ) AS xefile (TargetData, SessName)
      CROSS APPLY TargetData.nodes(N'//EventFileTarget/File') AS xmlsrc(data)
    ) AS InnerData(BasePath, SessName)
  ),
  SessionData([EventData]) AS 
  (
    SELECT CONVERT(xml, TargetData.event_data) FROM FileInfo CROSS APPLY 
      sys.fn_xe_file_target_read_file(FileInfo.XEPath, NULL, NULL, NULL) AS TargetData
  ), 
  src AS
  (
    SELECT 
      EndTimeUTC   = x.d.value(N'(@timestamp)[1]',                                  N'datetime2'),
      DatabaseID   = x.d.value(N'(data  [@name="database_id"]/value)[1]',           N'int'),
      [FileName]   = x.d.value(N'(data  [@name="file_name"]/value)[1]',             N'sysname'),
      Duration     = x.d.value(N'(data  [@name="duration"]/value)[1]',              N'int'),
      FileType     = x.d.value(N'(data  [@name="file_type"]/text)[1]',              N'varchar(4)'),
      Culprit      = x.d.value(N'(action[@name="sql_text"]/value)[1]',              N'nvarchar(max)'),
      IsAutomatic  = x.d.value(N'(data  [@name="is_automatic"]/value)[1]',          N'varchar(5)'),
      ChangeKB     = x.d.value(N'(data  [@name="size_change_kb"]/value)[1]',        N'bigint'),
      Principal    = x.d.value(N'(action[@name="server_principal_name"]/value)[1]', N'sysname'),
      username     = x.d.value(N'(action[@name="username"]/value)[1]',              N'sysname'),
      AppName      = x.d.value(N'(action[@name="client_app_name"]/value)[1]',       N'sysname'),
      HostName     = x.d.value(N'(action[@name="client_hostname"]/value)[1]',       N'sysname')
      --, [EventData] -- raw XML to troubleshoot specific events
    FROM SessionData CROSS APPLY EventData.nodes('/event') AS x(d)
  )
  SELECT 
    DatabaseName    = DB_NAME(DatabaseID), 
    [FileName], 
    DurationSeconds = CONVERT(decimal(18,3),Duration/1000000.0),
    StartTimeUTC    = CONVERT(datetime2(3), DATEADD(MICROSECOND, -Duration, EndTimeUTC)), 
    EndTimeUTC      = CONVERT(datetime2(3), EndTimeUTC),
    FileType, 
    Culprit = CASE WHEN Culprit IS NULL AND AppName LIKE N'Repl%' 
                   THEN AppName ELSE Culprit END, 
    IsAutomatic, 
    ChangeMB  = CONVERT(decimal(18,3), ChangeKB / 1024.0), 
    Principal = COALESCE([Principal], COALESCE(NULLIF(username,N''),N'?')),
    HostName, 
    App = CASE WHEN AppName LIKE N'%Management Studio%Query%' 
                    THEN N'SSMS - Query Window'
               WHEN AppName LIKE N'%Management Studio%'       
                    THEN N'SSMS - GUI!'
               ELSE AppName END--, [EventData] -- raw XML to troubleshoot specific events
  FROM src;

Ahora, cuando alguien quiere revisar eventos recientes de cambio de tamaño de archivo en cualquier servidor, ejecuta:

SELECT <cols>
  FROM UtilityDatabase.dbo.vwFileSizeChanges
  ORDER BY StartTimeUTC DESC;

Cuando deshabilita el seguimiento predeterminado, los archivos de seguimiento no se eliminan, por lo que cualquier evento anterior a ese cambio aún se puede revisar. Puedo tomar prestado el hecho de que el seguimiento predeterminado está codificado en la misma ruta que SERVERPROPERTY(N'ErrorLogFileName') y cree una segunda vista que combine los datos anteriores con más datos de la traza predeterminada:

CREATE VIEW dbo.vwFileSizeChanges_IncludingTrace
AS
  WITH dst AS
  (
    SELECT s,e,d 
      FROM (VALUES ('20190310','20191103',240),('20191103','20200308',300),
                   ('20200308','20201101',240),('20201101','20210314',300),
                   ('20210314','20211107',240)) AS dst(s,e,d)
      -- arbitrary date range to support DST conversions going a year+ each way
      -- will add 2022, 2023, etc. later (if DST is still a thing then)
  ),vars(TracePath) AS
  (
    SELECT REVERSE(SUBSTRING(p, CHARINDEX(N'\', p), 260)) + N'log.trc' FROM 
      (SELECT REVERSE((CONVERT(nvarchar(max), SERVERPROPERTY(N'ErrorLogFileName'))))) AS s(p)
  ), 
  trc AS
  (
    SELECT 
      t.DatabaseName, 
      t.[FileName], 
      DurationSeconds = CONVERT(decimal(18,3), t.Duration/1000000.0),
      StartTimeUTC = CONVERT(datetime2(3), DATEADD(MINUTE, COALESCE(st1.d,0), t.StartTime)),
      EndTimeUTC   = CONVERT(datetime2(3), DATEADD(MINUTE, COALESCE(st2.d,0), t.EndTime)),
      FileType = CASE WHEN t.EventClass IN (92, 94) THEN 'Data' 
	                  WHEN t.EventClass IN (93, 95) THEN 'Log' END,
      Culprit  = CASE WHEN t.TextData IS NULL AND t. ApplicationName LIKE N'Repl%' 
                      THEN t.ApplicationName ELSE t.TextData END, 
      IsAutomatic = 'true', 
      ChangeMB = CONVERT(bigint, t.IntegerData)*8/1024, 
      Principal = t.LoginName, 
      t.HostName, 
      App = CASE WHEN t.ApplicationName LIKE N'%Management Studio%Query%' 
                      THEN N'SSMS - Query Window'
                 WHEN t.ApplicationName LIKE N'%Management Studio%'
                      THEN N'SSMS - GUI!'
                 ELSE t.ApplicationName END --, [EventData] = CONVERT(xml, NULL)
    FROM vars CROSS APPLY sys.fn_trace_gettable(vars.TracePath, DEFAULT) AS t
    LEFT OUTER JOIN dst AS st1 ON  t.StartTime >= DATEADD(HOUR,2,st1.s) 
                               AND t.StartTime <  DATEADD(HOUR,2,st1.e)
    LEFT OUTER JOIN dst AS st2 ON  t.EndTime   >= DATEADD(HOUR,2,st2.s) 
                               AND t.EndTime   <  DATEADD(HOUR,2,st2.e)
    WHERE t.EventClass IN (92,93)
  )
  SELECT src='trace', * FROM trc
  UNION ALL
  SELECT src='xe',    * FROM dbo.vwFileSizeChanges;

Esta vista ajusta los datos de seguimiento (capturados en hora del este en todos nuestros servidores) a UTC y también maneja el horario de verano cuando corresponde. Si los datos se encuentran fuera del rango del CTE llamado dst , en su lugar, se expresará en hora del Este (y puede arreglar esto fácilmente agregando más rangos de horario de verano). Hay una columna adicional llamada src para que pueda consultar los datos de rastreo antiguos usando:

SELECT <cols>
  FROM UtilityDatabase.dbo.vwFileSizeChanges_IncludingTrace
  WHERE src = 'trace'
  ORDER BY StartTimeUTC DESC;

Advertencias

¡No existe tal cosa como un almuerzo gratis! Si bien confío en que eliminar el rastreo predeterminado no tendrá un impacto positivo en nuestras cargas de trabajo, o lo que es más probable, hay algunas cosas que debe tener en cuenta para su entorno si elige seguir mi camino:

  • Las bases de datos no son permanentes

    En mi definición de sesión de eventos extendidos, elegí no implementar collect_database_name , y en la vista anterior puede ver que resuelvo esto en tiempo de ejecución usando DB_NAME(database_id) . Existe un riesgo aquí, ya que alguien podría crear una base de datos, realizar un montón de actividades que generen una rotación de archivos y una paliza del disco, y luego eliminar la base de datos. El database_id expuesto en el XML ya no tiene sentido en este caso, y DB_NAME() devolverá NULL .

    Elegí este resultado en lugar de confiar únicamente en el nombre de la base de datos, porque la cadena de eventos anterior es mucho menos probable que un cambio de nombre de la base de datos (donde un database_id seguirá igual). En ese caso, es posible que esté buscando eventos que sucedieron en una base de datos, pero buscando con el nombre incorrecto (actual), dependiendo de cuándo ocurrieron los eventos.

    Si desea poder usar uno u otro, puede usar la siguiente definición de sesión en su lugar:

    ...
    ADD EVENT sqlserver.database_file_size_change
    (
      SET collect_database_name = (1)  
      ACTION
      (
        sqlserver.sql_text,
    ...

    Esto tampoco puede ser gratis, o sucedería por defecto, pero confieso que nunca probé el impacto de agregar eso a la colección.

  • Los informes SSMS serán ligeramente menos fiables

    Un efecto secundario de deshabilitar el seguimiento predeterminado es la interrupción de algunos de los "Informes estándar" de Management Studio. Encuesté a nuestros equipos antes de hacer esto, y querrá hacer lo mismo para asegurarse de que sus usuarios no confíen en ninguno de estos. También querrá recordarles que actualmente no se puede confiar en los informes de todos modos, por la misma razón que no puedo confiar directamente en el seguimiento predeterminado:solo pueden extraer datos que todavía están en el seguimiento. Un informe vacío no significa necesariamente que no sucedieron eventos; simplemente podría significar que la información ya no está disponible. Si este es realmente el lugar donde un equipo desea consumir esta información, podría asegurarme de que sea confiable enviándoles informes personalizados que utilicen una fuente más confiable.

    Los siguientes informes son los que pude ver derivar al menos parte de su información del rastreo predeterminado, y por qué no necesitamos los informes incluso si se puede confiar en ellos:

    Historial de cambios de esquema Ya contamos con control de código fuente, un riguroso proceso de revisión/implementación y disparadores DDL que capturan información sobre los cambios de esquema.
    Historial de cambios de configuración
    y
    Consumo de memoria
    Nuestra herramienta de monitoreo nos informa sobre los cambios de configuración a nivel de instancia, por lo que este informe en SSMS es redundante.
    Errores de inicio de sesión Estos están en el registro de errores (y en el visor de eventos) porque, como estándar, habilitamos la auditoría "Solo inicios de sesión fallidos" para todas las instancias de SQL Server. Algunos servidores también tienen auditorías formales adicionales por motivos de cumplimiento.
    Uso de disco Entre otra información, aquí se enumeran los eventos de crecimiento automático y reducción automática del seguimiento predeterminado, que ahora capturamos mediante eventos extendidos.
    Copia de seguridad y restauración de eventos Esta información está disponible en msdb.dbo.backupset si alguna vez la necesitamos, pero también se incluye en nuestra automatización en torno a la copia de seguridad y la restauración (nunca buscamos el seguimiento predeterminado para esta información).
    Historial de coherencia de la base de datos Al igual que con las copias de seguridad, contamos con automatización basada en DBCC CHECKDB; si alguien salió de esto y ejecutó algo manualmente, seguirá apareciendo en el registro de errores. Y tenemos mucho más control sobre cuánto tiempo mantenemos los registros de errores y con qué frecuencia los reciclamos. Reciclamos todas las noches para que sea más fácil encontrar un evento que sospechamos que sucedió en un día determinado en el pasado.

    Conclusión

    Este fue un proyecto divertido pero complicado, y estoy satisfecho con el resultado hasta ahora. ¡Gracias por acompañarnos!

    [ Parte 1 | Parte 2 | Parte 3 ]