sql >> Database >  >> RDS >> Database

Het standaardspoor verwijderen - Deel 3

[ Deel 1 | Deel 2 | Deel 3 ]

In deel 1 van deze serie heb ik uitgelegd hoe ik tot de conclusie kwam dat we de standaardtracering moesten uitschakelen. In deel 2 liet ik de Extended Events-sessie zien die ik heb ingezet om alle bestandsgroottewijzigingsgebeurtenissen vast te leggen. In dit bericht wil ik de weergaven laten zien die ik heb gemaakt om het gebruik van de evenementgegevens voor mensen gemakkelijker te maken, en ook om enkele kanttekeningen te plaatsen.

Verteerbare weergaven

Eerst heb ik een weergave gemaakt die de belangrijke bits van de Extended Events-sessiegegevens blootlegt en deze in de hulpprogrammadatabase plaatst die op elke instantie bestaat:

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;

Als iemand nu recente wijzigingen in bestandsgrootte op een server wil bekijken, voeren ze het volgende uit:

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

Wanneer u de standaard tracering uitschakelt, worden de traceringsbestanden niet verwijderd, dus alle gebeurtenissen van vóór die wijziging kunnen nog steeds worden gecontroleerd. Ik kan lenen van het feit dat de standaardtracering hard gecodeerd is naar hetzelfde pad als SERVERPROPERTY(N'ErrorLogFileName') , en maak een tweede weergave die de bovenstaande gegevens combineert met meer gegevens van de standaardtracering:

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;

Deze weergave past de traceringsgegevens (vastgelegd in Oosterse tijd op al onze servers) aan naar UTC en verwerkt ook de zomertijd waar nodig. Als de gegevens buiten het bereik vallen van de CTE genaamd dst , wordt het in plaats daarvan uitgedrukt in Oosterse tijd (en u kunt dit eenvoudig oplossen door meer DST-bereiken toe te voegen). Er is een extra kolom genaamd src zodat u de oude traceergegevens kunt opvragen met:

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

Voorbehoud

Er bestaat niet zoiets als een gratis lunch! Hoewel ik er zeker van ben dat het verwijderen van de standaardtracering geen of, veel waarschijnlijker, een positieve impact zal hebben op onze workloads, zijn er enkele dingen waarmee u rekening moet houden voor uw omgeving als u ervoor kiest om mijn pad te volgen:

  1. Databases zijn niet permanent

    In mijn Extended Events-sessiedefinitie heb ik ervoor gekozen om collect_database_name niet te implementeren , en in de bovenstaande weergave kunt u zien dat ik dit tijdens runtime oplos met DB_NAME(database_id) . Er is hier een risico, dat iemand een database kan maken, een heleboel activiteiten kan uitvoeren die bestandsverloop en schijfgeseling veroorzaken, en vervolgens de database kan laten vallen. De database_id blootgesteld in de XML is in dit geval niet langer zinvol, en DB_NAME() retourneert NULL .

    Ik heb voor deze uitkomst gekozen in plaats van alleen te vertrouwen op de databasenaam, omdat de bovenstaande reeks gebeurtenissen veel minder waarschijnlijk is dan het hernoemen van een database (waarbij een database_id blijft hetzelfde). In dat geval zoekt u misschien naar gebeurtenissen die met een database zijn gebeurd, maar zoekt u met de verkeerde (huidige) naam, afhankelijk van wanneer de gebeurtenissen plaatsvonden.

    Als u de een of de ander wilt gebruiken, kunt u in plaats daarvan de volgende sessiedefinitie gebruiken:

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

    Dit kan ook niet gratis zijn, anders zou het standaard gebeuren, maar ik moet bekennen dat ik de impact van het toevoegen ervan aan de collectie nooit heb getest.

  2. SSMS-rapporten zijn iets minder betrouwbaar

    Een neveneffect van het uitschakelen van de standaardtracering is dat sommige "Standaardrapporten" van Management Studio worden verstoord. Ik heb onze teams ondervraagd voordat ik dit deed, en u wilt hetzelfde doen om ervoor te zorgen dat uw gebruikers niet op een van deze vertrouwen. U wilt ze er ook aan herinneren dat er op dit moment toch niet op de rapporten kan worden vertrouwd, om dezelfde reden dat ik niet rechtstreeks op de standaardtracering kan vertrouwen - ze kunnen alleen gegevens ophalen die zich nog in de trace bevinden. Een leeg rapport betekent niet noodzakelijkerwijs dat er geen gebeurtenissen hebben plaatsgevonden; het zou zomaar kunnen betekenen dat de informatie niet langer beschikbaar is. Als dit echt is waar een team deze informatie wilde gebruiken, zou ik ervoor kunnen zorgen dat deze betrouwbaar is door ze aangepaste rapporten te sturen die een betrouwbaardere bron gebruiken.

    Van de volgende rapporten kon ik zien dat ze ten minste een deel van hun informatie afleiden uit de standaardtracering, en waarom we de rapporten niet nodig hebben, zelfs als ze te vertrouwen zijn:

    Geschiedenis van schemawijzigingen We hebben al broncontrole, een rigoureus beoordelings-/implementatieproces en DDL-triggers die informatie over schemawijzigingen vastleggen.
    Geschiedenis van configuratiewijzigingen
    en
    Geheugenverbruik
    Onze monitoringtool vertelt ons over configuratiewijzigingen op instantieniveau, dus dit rapport in SSMS is overbodig.
    Inlogfouten Deze staan ​​in het foutenlogboek (en de gebeurtenisviewer) omdat we standaard de controle "Alleen mislukte aanmeldingen" inschakelen voor alle SQL Server-instanties. Sommige servers hebben ook aanvullende formele controles om nalevingsredenen.
    Schijfgebruik Hieronder worden onder meer de autogrowth- en autoshrink-gebeurtenissen van de standaardtracering weergegeven, die we nu vastleggen met behulp van Extended Events.
    Back-up en herstel van gebeurtenissen Deze informatie is direct beschikbaar in msdb.dbo.backupset als we het ooit nodig hebben, maar dit is ook opgenomen in onze automatisering rond back-up en herstel (we kijken nooit naar de standaardtracering voor deze informatie).
    Databaseconsistentiegeschiedenis Net als bij back-ups hebben we automatisering gebouwd rond DBCC CHECKDB; als iemand hier buiten is gegaan en iets handmatig heeft uitgevoerd, wordt het nog steeds weergegeven in het foutenlogboek. En we hebben veel meer controle over hoe lang we foutenlogboeken bewaren en hoe vaak we ze recyclen. We recyclen elke nacht, zodat het gemakkelijker is om een ​​gebeurtenis te vinden waarvan we vermoeden dat deze op een bepaalde dag in het verleden heeft plaatsgevonden.

Conclusie

Dit was een leuk maar ingewikkeld project en ik ben tot nu toe tevreden met het resultaat. Bedankt voor het meerijden!

[ Deel 1 | Deel 2 | Deel 3 ]


  1. Prestatieoverwegingen voor tijdelijke gegevens in Oracle

  2. DATE() Voorbeelden – MySQL

  3. Controleer of er een rij bestaat, anders invoegen

  4. Ruby 'pg' gem linkt naar verkeerde kopie van libpq.5.dylib (op OSX)