sql >> Databasteknik >  >> RDS >> Database

Ta bort standardspåret – Del 3

[ Del 1 | Del 2 | Del 3 ]

I del 1 av den här serien förklarade jag hur jag kom fram till att vi skulle inaktivera standardspårningen. I del 2 visade jag Extended Events-sessionen som jag distribuerade för att fånga alla filstorleksändringshändelser. I det här inlägget vill jag visa vyerna jag skapade för att göra konsumtionen av händelsedata lättare för människor, och även för att förklara några varningar.

Smältbara vyer

Först skapade jag en vy som skulle exponera de viktiga bitarna från sessionsdata för utökade händelser och lägga in den i verktygsdatabasen som finns på varje instans:

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;

Nu, när någon vill granska de senaste händelserna för filstorleksändring på valfri server, kör de:

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

När du inaktiverar standardspårningen raderas inte spårningsfilerna, så alla händelser från före den ändringen går fortfarande att granska. Jag kan låna från det faktum att standardspårningen är hårdkodad till samma sökväg som SERVERPROPERTY(N'ErrorLogFileName') , och skapa en andra vy som förenar ovanstående data med mer data från standardspårningen:

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;

Denna vy justerar spårningsdata (fångad i österländsk tid på alla våra servrar) till UTC och hanterar även sommartid där så är lämpligt. Om data faller utanför intervallet för CTE som kallas dst , kommer det att uttryckas i österländsk tid istället (och du kan enkelt fixa detta genom att lägga till fler sommarintervall). Det finns en extra kolumn som heter src så att du kan söka efter gamla spårningsdata med:

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

Varningar

Det finns inget som heter gratis lunch! Även om jag är övertygad om att ta bort standardspårningen kommer att ha noll eller, mycket mer troligt, en positiv inverkan på våra arbetsbelastningar, men det finns några saker att tänka på för din miljö om du väljer att följa min väg:

  1. Databaser är inte permanenta

    I min definition av sessioner för utökade händelser valde jag att inte implementera collect_database_name , och i vyn ovan kan du se att jag löser detta vid körning med DB_NAME(database_id) . Det finns en risk här, genom att någon kan skapa en databas, utföra en massa aktiviteter som skapar filchurn och disktrassling, och sedan släppa databasen. database_id exponerad i XML är inte längre meningsfull i det här fallet, och DB_NAME() returnerar NULL .

    Jag valde detta resultat framför att enbart förlita mig på databasnamn, eftersom ovanstående händelsekedja är mycket mindre sannolikt än ett databasbyte (där ett database_id kommer att förbli densamma). I så fall kanske du letar efter händelser som hände med en databas, men söker med fel (aktuella) namn, beroende på när händelserna inträffade.

    Om du vill kunna använda det ena eller det andra kan du istället använda följande sessionsdefinition:

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

    Det här kan inte heller vara gratis, annars skulle det hända som standard, men jag ska erkänna att jag aldrig har testat effekten av att lägga till det i samlingen.

  2. SSMS-rapporter blir något mindre tillförlitliga

    En bieffekt av att inaktivera standardspårningen stör några av Management Studios "Standard Reports". Jag frågade våra team innan jag gjorde det här, och du vill göra detsamma för att se till att dina användare inte litar på någon av dessa. Du vill också påminna dem om att rapporterna för närvarande inte går att lita på hur som helst, av samma anledning som jag inte kan lita på standardspårningen direkt – de kan bara dra data som fortfarande finns i spåret. En tom rapport betyder inte nödvändigtvis att inga händelser inträffade; det kan helt enkelt betyda att informationen inte längre är tillgänglig. Om det verkligen var här ett team ville konsumera denna information, skulle jag kunna se till att den är tillförlitlig genom att skicka anpassade rapporter till dem som använder en mer pålitlig källa.

    Följande rapporter är de som jag kunde se härleda åtminstone en del av sin information från standardspårningen, och varför vi inte behöver rapporterna även om de kunde lita på:

    Schemaändringshistorik Vi har redan källkontroll, en noggrann granskning/implementeringsprocess och DDL-utlösare på plats som fångar information om schemaändringar.
    Historik för konfigurationsändringar
    och
    Minnesförbrukning
    Vårt övervakningsverktyg berättar för oss om konfigurationsändringar på instansnivå, så den här rapporten i SSMS är överflödig.
    Inloggningsfel Dessa finns i felloggen (och händelsevisaren) eftersom vi som standard aktiverar granskning av "endast misslyckade inloggningar" för alla SQL Server-instanser. Vissa servrar har även ytterligare formell granskning av efterlevnadsskäl.
    Diskanvändning Bland annat listar detta händelserna för autotillväxt och autokrympning från standardspårningen, som vi nu fångar med hjälp av utökade händelser.
    Säkerhetskopiera och återställa händelser Denna information är lättillgänglig i msdb.dbo.backupset om vi någonsin behöver den, men den rullas också in i vår automatisering kring säkerhetskopiering och återställning (vi tittar aldrig på standardspårningen för denna information).
    Databaskonsistenshistorik Som med säkerhetskopieringar har vi automatisering byggd kring DBCC CHECKDB; om någon gick utanför detta och körde något manuellt, kommer det fortfarande att dyka upp i felloggen. Och vi har mycket mer kontroll över hur länge vi sparar felloggar och hur ofta vi återvinner dem. Vi återvinner varje natt så att det är lättare att hitta en händelse som vi misstänker har hänt en viss dag i det förflutna.

Slutsats

Det här var ett roligt men komplicerat projekt, och jag är nöjd med resultatet så här långt. Tack för att du följde med!

[ Del 1 | Del 2 | Del 3 ]


  1. Bör varje användartabell ha ett klusterindex?

  2. Skrivskyddad routing för en alltid på

  3. MySQL Tutorial – En nybörjarguide för att lära dig MySQL

  4. Hur man konverterar versaler till gemener i MySQL