Database
 sql >> Baza danych >  >> RDS >> Database

Usuwanie domyślnego śladu – część 3

[ Część 1 | Część 2 | Część 3 ]

W części 1 tej serii wyjaśniłem, w jaki sposób doszedłem do wniosku, że powinniśmy wyłączyć domyślne śledzenie. W części 2 pokazałem sesję Extended Events, którą wdrożyłem do przechwytywania wszystkich zdarzeń zmiany rozmiaru pliku. W tym poście chcę pokazać widoki, które stworzyłem, aby ułatwić ludziom korzystanie z danych o wydarzeniach, a także wyjaśnić pewne zastrzeżenia.

Widoki strawne

Najpierw utworzyłem widok, który eksponowałby ważne fragmenty danych sesji Extended Events i umieściłem go w bazie danych narzędzi, która istnieje w każdej instancji:

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;

Teraz, gdy ktoś chce przejrzeć ostatnie zdarzenia zmiany rozmiaru pliku na dowolnym serwerze, uruchamia:

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

Po wyłączeniu śledzenia domyślnego pliki śledzenia nie są usuwane, więc wszystkie zdarzenia sprzed tej zmiany są nadal dostępne do przeglądania. Mogę pożyczyć z faktu, że domyślny ślad jest zakodowany na sztywno w tej samej ścieżce, co SERVERPROPERTY(N'ErrorLogFileName') i utwórz drugi widok, który łączy powyższe dane z większą ilością danych z domyślnego śledzenia:

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;

Ten widok dostosowuje dane śledzenia (przechwycone w czasie wschodnim na wszystkich naszych serwerach) do czasu UTC, a także w razie potrzeby obsługuje czas letni. Jeśli dane wykraczają poza zakres CTE o nazwie dst , zostanie on wyrażony w czasie wschodnim (możesz to łatwo naprawić, dodając więcej zakresów czasu letniego). Istnieje dodatkowa kolumna o nazwie src więc możesz sprawdzić stare dane śledzenia za pomocą:

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

Ostrzeżenia

Nie ma czegoś takiego jak darmowy lunch! Chociaż jestem przekonany, że usunięcie domyślnego śledzenia będzie miało zerowy lub, co bardziej prawdopodobne, pozytywny wpływ na nasze obciążenia, należy pamiętać o kilku rzeczach w swoim środowisku, jeśli zdecydujesz się podążać moją ścieżką:

  1. Bazy danych nie są trwałe

    W mojej definicji sesji Extended Events zdecydowałem się nie implementować collect_database_name , aw powyższym widoku widać, że rozwiązuję to w czasie wykonywania za pomocą DB_NAME(database_id) . Istnieje tutaj ryzyko, że ktoś mógłby stworzyć bazę danych, wykonać szereg czynności, które powodują churn plików i thrashing dysku, a następnie usunąć bazę danych. database_id ujawnione w XML nie ma już znaczenia w tym przypadku, a DB_NAME() zwróci NULL .

    Wybrałem ten wynik zamiast polegać wyłącznie na nazwie bazy danych, ponieważ powyższy łańcuch zdarzeń jest znacznie mniej prawdopodobny niż zmiana nazwy bazy danych (gdzie database_id pozostanie bez zmian). W takim przypadku możesz szukać zdarzeń, które miały miejsce w bazie danych, ale szukając przy użyciu niewłaściwej (bieżącej) nazwy, w zależności od tego, kiedy zdarzenia miały miejsce.

    Jeśli chcesz mieć możliwość korzystania z jednego lub drugiego, możesz zamiast tego użyć następującej definicji sesji:

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

    To też nie może być bezpłatne, w przeciwnym razie stałoby się to domyślnie, ale przyznam, że nigdy nie testowałem wpływu dodania tego do kolekcji.

  2. Raporty SSMS będą nieco mniej niezawodne

    Efektem ubocznym wyłączenia śledzenia domyślnego jest zakłócenie działania niektórych „Raportów standardowych” programu Management Studio. Zanim to zrobiłem, przepytałem nasze zespoły i będziesz chciał zrobić to samo, aby upewnić się, że Twoi użytkownicy nie polegają na żadnym z nich. Będziesz także chciał im przypomnieć, że obecnie i tak nie można polegać na raportach, z tego samego powodu, dla którego nie mogę bezpośrednio polegać na domyślnym śledzeniu – mogą pobierać tylko dane, które nadal znajdują się w śledzeniu. Pusty raport nie musi koniecznie oznaczać, że żadne wydarzenia się nie wydarzyły; może to po prostu oznaczać, że informacje nie są już dostępne. Jeśli to naprawdę jest miejsce, w którym zespół chciałby wykorzystać te informacje, mógłbym upewnić się, że są one wiarygodne, wysyłając im niestandardowe raporty, które korzystają z bardziej wiarygodnego źródła.

    Następujące raporty są tymi, które, jak zauważyłem, czerpią przynajmniej część swoich informacji z domyślnego śledzenia i dlaczego nie potrzebujemy raportów, nawet jeśli można im ufać:

    Historia zmian schematu Mamy już kontrolę źródła, rygorystyczny proces przeglądu/wdrażania oraz wyzwalacze DDL, które przechwytują informacje o zmianach schematu.
    Historia zmian konfiguracji
    i
    Zużycie pamięci
    Nasze narzędzie do monitorowania informuje nas o zmianach konfiguracji na poziomie instancji, więc ten raport w SSMS jest zbędny.
    Nieudane logowanie Są one w dzienniku błędów (i przeglądarce zdarzeń), ponieważ standardowo włączamy inspekcję „Tylko nieudane logowanie” dla wszystkich instancji SQL Server. Niektóre serwery mają również dodatkowe formalne audyty ze względu na zgodność.
    Wykorzystanie dysku Między innymi informacjami, ta lista zawiera zdarzenia autowzrostu i autozmniejszania z domyślnego śledzenia, które teraz przechwytujemy za pomocą zdarzeń rozszerzonych.
    Zdarzenia tworzenia kopii zapasowych i przywracania Te informacje są łatwo dostępne w msdb.dbo.backupset, jeśli kiedykolwiek ich potrzebujemy, ale są one również wprowadzane do naszej automatyzacji wokół tworzenia kopii zapasowych i przywracania (nigdy nie patrzymy na domyślny ślad dla tych informacji).
    Historia spójności bazy danych Podobnie jak w przypadku kopii zapasowych, mamy automatyzację zbudowaną wokół DBCC CHECKDB; jeśli ktoś wyszedł poza to i uruchomił coś ręcznie, nadal będzie to widoczne w dzienniku błędów. I mamy znacznie większą kontrolę nad tym, jak długo przechowujemy logi błędów i jak często je przetwarzamy. Odzyskujemy się co noc, aby łatwiej było znaleźć zdarzenie, które, jak podejrzewamy, miało miejsce danego dnia w przeszłości.

Wniosek

To był fajny, ale skomplikowany projekt i jak na razie jestem zadowolony z wyniku. Dziękujemy za jazdę!

[ Część 1 | Część 2 | Część 3 ]


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sztuka wyodrębniania zależności i danych w testach jednostkowych bazy danych

  2. Typy danych SQL:5 najgorszych wyborów, których musisz dzisiaj zatrzymać

  3. Minimalizowanie wpływu poszerzenia kolumny TOŻSAMOŚĆ – część 2

  4. Wprowadzenie do zatrzasków

  5. Podłączanie 32-bitowej aplikacji do jBASE