Database
 sql >> Database >  >> RDS >> Database

Rimozione della traccia predefinita – Parte 3

[ Parte 1 | Parte 2 | Parte 3]

Nella parte 1 di questa serie, ho spiegato come sono arrivato alla conclusione che dovremmo disabilitare la traccia predefinita. Nella parte 2, ho mostrato la sessione di eventi estesi che ho distribuito per acquisire tutti gli eventi di modifica delle dimensioni dei file. In questo post, voglio mostrare le viste che ho creato per rendere più facile il consumo dei dati dell'evento per le persone e anche per spiegare alcuni avvertimenti.

Viste digeribili

Innanzitutto, ho creato una vista che esponesse i bit importanti dai dati della sessione degli eventi estesi e li inserissi nel database di utilità che esiste in ogni istanza:

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;

Ora, quando qualcuno vuole rivedere gli eventi recenti di modifica delle dimensioni dei file su qualsiasi server, esegue:

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

Quando si disabilita la traccia predefinita, i file di traccia non vengono eliminati, quindi tutti gli eventi precedenti a tale modifica sono ancora verificabili. Posso prendere in prestito dal fatto che la traccia predefinita è hardcoded nello stesso percorso di SERVERPROPERTY(N'ErrorLogFileName') e crea una seconda vista che unisca i dati sopra con più dati dalla traccia predefinita:

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;

Questa visualizzazione regola i dati di traccia (acquisiti nell'ora orientale su tutti i nostri server) in base all'ora UTC e gestisce anche l'ora legale ove appropriato. Se i dati non rientrano nell'intervallo del CTE denominato dst , sarà invece espresso nell'ora orientale (e puoi facilmente risolverlo aggiungendo più intervalli di DST). C'è una colonna aggiuntiva chiamata src quindi puoi interrogare i vecchi dati di traccia utilizzando:

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

Avvertenze

Non esiste un pranzo gratis! Anche se sono fiducioso che la rimozione della traccia predefinita avrà zero o, molto più probabilmente, un impatto positivo sui nostri carichi di lavoro, ci sono alcune cose da tenere a mente per il tuo ambiente se scegli di seguire il mio percorso:

  • I database non sono permanenti

    Nella definizione della mia sessione Eventi estesi, ho scelto di non implementare collect_database_name e nella vista sopra puoi vedere che lo risolvo in fase di esecuzione usando DB_NAME(database_id) . C'è un rischio qui, in quanto qualcuno potrebbe creare un database, eseguire una serie di attività che creano churn di file e thrashing del disco, quindi eliminare il database. Il database_id esposto nell'XML non ha più significato in questo caso e DB_NAME() restituirà NULL .

    Ho scelto questo risultato piuttosto che fare affidamento esclusivamente sul nome del database, perché la catena di eventi sopra è molto meno probabile di una ridenominazione del database (dove a database_id rimarrà lo stesso). In tal caso, potresti cercare eventi accaduti in un database, ma utilizzando il nome (attuale) errato, a seconda di quando si sono verificati gli eventi.

    Se vuoi essere in grado di utilizzare l'uno o l'altro, puoi invece utilizzare la seguente definizione di sessione:

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

    Neanche questo può essere gratuito, o accadrebbe per impostazione predefinita, ma confesso che non ho mai testato l'impatto dell'aggiunta di questo alla raccolta.

  • I rapporti SSMS saranno leggermente meno affidabili

    Un effetto collaterale della disattivazione della traccia predefinita è l'interruzione di alcuni "rapporti standard" di Management Studio. Ho interrogato i nostri team prima di farlo e tu vorrai fare lo stesso per assicurarti che i tuoi utenti non facciano affidamento su nessuno di questi. Dovrai anche ricordare loro che i rapporti attualmente non possono essere comunque invocati, per lo stesso motivo per cui non posso fare affidamento direttamente sulla traccia predefinita:possono solo estrarre i dati che sono ancora nella traccia. Un rapporto vuoto non significa necessariamente che non si siano verificati eventi; potrebbe semplicemente significare che le informazioni non sono più disponibili. Se questo è davvero il punto in cui un team desidera utilizzare queste informazioni, potrei assicurarmi che siano affidabili inviando loro rapporti personalizzati che utilizzano una fonte più affidabile.

    I seguenti rapporti sono quelli che ho potuto vedere derivano almeno alcune delle loro informazioni dalla traccia predefinita e perché non abbiamo bisogno dei rapporti anche se potrebbero essere attendibili:

    Cronologia modifiche schema Abbiamo già il controllo del codice sorgente, un rigoroso processo di revisione/distribuzione e attivatori DDL in atto che acquisiscono informazioni sulle modifiche allo schema.
    Cronologia modifiche alla configurazione
    e
    >Consumo di memoria
    Il nostro strumento di monitoraggio ci informa sulle modifiche alla configurazione a livello di istanza, quindi questo rapporto in SSMS è ridondante.
    Errori di accesso Questi sono nel registro degli errori (e nel visualizzatore di eventi) perché, come standard, abilitiamo il controllo "Solo accessi non riusciti" per tutte le istanze di SQL Server. Alcuni server hanno anche un controllo formale aggiuntivo per motivi di conformità.
    Utilizzo del disco Tra le altre informazioni, questo elenca gli eventi di autocrescita e riduzione automatica dalla traccia predefinita, che ora acquisiamo utilizzando gli eventi estesi.
    Eventi di backup e ripristino Queste informazioni sono prontamente disponibili in msdb.dbo.backupset se mai ne avessimo bisogno, ma sono anche integrate nella nostra automazione relativa al backup e al ripristino (non esaminiamo mai la traccia predefinita per queste informazioni).
    Cronologia della coerenza del database Come per i backup, abbiamo l'automazione basata su DBCC CHECKDB; se qualcuno è andato al di fuori di questo ed ha eseguito qualcosa manualmente, verrà comunque visualizzato nel registro degli errori. E abbiamo molto più controllo su quanto tempo conserviamo i registri degli errori e quanto spesso li ricicliamo. Ricicliamo ogni notte in modo che sia più facile trovare un evento che sospettiamo sia accaduto in un determinato giorno nel passato.

    Conclusione

    Questo è stato un progetto divertente ma complicato e sono soddisfatto del risultato ottenuto finora. Grazie per essere andato avanti!

    [ Parte 1 | Parte 2 | Parte 3]