sql >> データベース >  >> RDS >> Database

デフォルトのトレースの削除–パート2

    [パート1|パート2|パート3]

    このシリーズの最初の投稿では、デフォルトのトレースが私たちに適していないことを判断するために使用した分析を示しました。その場所で実際に収集する必要のある情報(ファイルサイズの変更)と、これをユーザーに公開する方法を検討しながら、デフォルトのトレースについて次の点を検討しました。

    • 自動のみをキャプチャします イベント;
    • 別の理由(DDLなど)でもキャプチャされた幸運でない限り、イベントの原因となった「原因」バッチはキャプチャされません。と、
    • 現地時間を使用してイベントをキャプチャします(サーバーは東部であり、DSTに従います)。

    その防御において、それはそれらの自動イベントに関する多くの重要な情報をキャプチャします。デフォルトのトレースを無効にした後でも、変更前に発生し、それらのファイルにキャプチャされたイベントを確認したい場合があります。ただし、デフォルトのトレースが無効になると、その行はsys.tracesに存在しなくなります。 、したがって、.trcへのパスを特定できません そこからのファイル。デフォルトのトレースの柔軟性がないことが実際にメリットをもたらすのはここです。ファイルは、SERVERPROPERTY(N'ErrorLogFileName')と同じフォルダーに存在するようにハードコードされています。 。したがって、デフォルトのトレースが無効になっている場合でも、次のクエリを使用してファイルからデータをプルできます(UTCでデータを表示するように調整されています):

    ;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)
    ),    -- will add 2022, 2023, etc. later (if DST is still a thing then)
    p AS
    (
     
        SELECT TracePath = 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 src = 'trc', 
          t.DatabaseName, 
          t.[FileName], 
          DurationSeconds = CONVERT(decimal(18,3),Duration/1000000.0),
          StartTimeUTC = DATEADD(MINUTE, COALESCE(st1.d,0), t.StartTime),
          EndTimeUTC   = DATEADD(MINUTE, COALESCE(st2.d,0), t.EndTime),
          FileType = CASE t.EventClass WHEN 92 THEN 'Data' WHEN 93 THEN 'Log' END,
          Culprit = TextData, 
          IsAutomatic = 'true', 
          ChangeMB = CONVERT(bigint, IntegerData)*8/1024, 
          Principal = t.LoginName, 
          t.HostName, 
          App = CASE WHEN ApplicationName LIKE N'%Management Studio%Query%' 
                          THEN N'SSMS - Query Window'
                     WHEN ApplicationName LIKE N'%Management Studio%'
                          THEN N'SSMS - GUI!'
                     ELSE ApplicationName END
        FROM p CROSS APPLY sys.fn_trace_gettable(p.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 * 
      FROM trc
      ORDER BY StartTimeUTC DESC;

    1台のサーバーからのサンプル結果。手動および自動のイベントが確実に発生しました(クリックして拡大):

    交換を書く

    これを置き換えるために作成した拡張イベントセッションは、手動のファイルサイズの変更と、自動イベントの原因となったクエリテキストもキャプチャします。

    CREATE EVENT SESSION FileSizeChanges ON SERVER 
    ADD EVENT sqlserver.database_file_size_change
    (
      ACTION
      (
        sqlserver.sql_text,
        sqlserver.client_app_name,
        sqlserver.client_hostname,
        sqlserver.username,
        sqlserver.server_principal_name
      )
    )
    ADD TARGET package0.event_file
    (
      SET filename       = N'W:\SomePath\FileSizeChanges.xel',
      MAX_FILE_SIZE      = 100, -- MB
      MAX_ROLLOVER_FILES = 100  -- 100 MB x 100 = max 10 GB
    )
    WITH
    (
      MAX_MEMORY            = 8192 KB,
      EVENT_RETENTION_MODE  = ALLOW_SINGLE_EVENT_LOSS,
      MAX_DISPATCH_LATENCY  = 30 SECONDS,
      MAX_EVENT_SIZE        = 0 KB,
      TRACK_CAUSALITY       = OFF,
      STARTUP_STATE         = ON
    );
     
    ALTER EVENT SESSION FileSizeChanges ON SERVER STATE = START;

    usernameのように見えますが およびserver_principal_name 冗長かもしれませんが、実際には後者がNULLであるケースを見つけました (そして、この問題はしばらくの間発生しているようです)。

    結果の確認

    2月22日にそのセッションを有効にしたため、12日にキャプチャされたデフォルトのトレースのイベントが欠落していますが、23日からの単一の自動成長イベントよりも多くキャプチャされました。次のクエリを実行して、上記と同じ形状の結果を取得しました。

    ;WITH FileInfo(XEPath) AS
    (
      SELECT LEFT(BasePath,COALESCE(NULLIF(CHARINDEX(SessionName,BasePath)-1,-1),0)) 
             + SessionName + N'*.xel' 
        FROM
        (
          SELECT xmlsrc.data.value(N'(@name)[1]', N'nvarchar(max)'), SessionName
            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, SessionName)
            CROSS APPLY TargetData.nodes(N'//EventFileTarget/File') AS xmlsrc(data)
        ) AS InnerData(BasePath, SessionName)
    ),
    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')
      FROM SessionData CROSS APPLY EventData.nodes(N'/event') AS x(d)
    )
    SELECT 
      src = 'xe', 
      DatabaseName    = DB_NAME(DatabaseID), 
      [FileName], 
      DurationSeconds = CONVERT(decimal(18,3), Duration/1000000.0),
      StartTimeUTC    = DATEADD(MICROSECOND, -Duration, EndTimeUTC), 
      EndTimeUTC,
      FileType, 
      Culprit, 
      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
    FROM src
    ORDER BY StartTimeUTC DESC;

    結果は、UIから「データベースの縮小」タスクを実行する(クリックして拡大)など、私が楽しんだ追加の楽しみを示しています。

    どこにでも展開

    これで、どのサーバーでもファイルサイズ変更イベントの全体像を把握できると確信し、展開するときが来ました。 CMSクエリウィンドウを使用して、最初にすべての場所でデフォルトのトレースを無効にし、show advanced optionsを設定しました 私が見つけた方法に戻る:

    IF EXISTS 
    (
      SELECT 1 FROM sys.configurations 
        WHERE name = N'default trace enabled' 
        AND value_in_use = 1
    )
    BEGIN
      DECLARE @OriginalAdvancedOptions bit = 
      (
        SELECT CONVERT(bit, value_in_use)
          FROM sys.configurations 
          WHERE name = N'show advanced options'
      );
     
      IF @OriginalAdvancedOptions = 0 -- need to turn this on if it's not already
      BEGIN
        EXEC sys.sp_configure @configname = N'show advanced options', @configvalue = 1;
        RECONFIGURE WITH OVERRIDE;
      END
     
      EXEC   sys.sp_configure @configname = N'default trace enabled', @configvalue = 0;
     
      IF @OriginalAdvancedOptions = 0 -- need to set it back (else leave it)
      BEGIN
        EXEC sys.sp_configure @configname = N'show advanced options', @configvalue = 0;
      END
     
      RECONFIGURE WITH OVERRIDE;
    END
    GO

    次に、拡張イベントセッションを作成するには、動的SQLを使用する必要があります。これは、サーバーによってはSERVERPROPERTY(N'ErrorLogFileName')のパスが異なる場合があるためです。 そして、その引数はパラメータ化できません。

    DECLARE @path nvarchar(max) = (SELECT REVERSE(SUBSTRING(p, CHARINDEX(N'\', p), 4000)) 
      FROM (SELECT REVERSE((CONVERT(nvarchar(max), SERVERPROPERTY(N'ErrorLogFileName'))))) AS s(p));
     
    IF EXISTS (SELECT 1 FROM sys.dm_xe_sessions WHERE name = N'FileSizeChanges')
    BEGIN
      EXEC sys.sp_executesql N'DROP EVENT SESSION FileSizeChanges ON SERVER;';
    END
     
    DECLARE @sql nvarchar(max) = N' CREATE EVENT SESSION FileSizeChanges ON SERVER 
    ADD EVENT sqlserver.database_file_size_change
    (
      ACTION
      (
        sqlserver.sql_text,
        sqlserver.client_app_name,
        sqlserver.client_hostname,
        sqlserver.username,
        sqlserver.server_principal_name
      )
    )
    ADD TARGET package0.event_file
    (
      SET filename       = ''' + @path + N'FileSizeChanges.xel'',
      MAX_FILE_SIZE      = 100, -- MB
      MAX_ROLLOVER_FILES = 100  -- 100 MB x 100 = max 10 GB
    )
    WITH
    (
      MAX_MEMORY            = 8192 KB,
      EVENT_RETENTION_MODE  = ALLOW_SINGLE_EVENT_LOSS,
      MAX_DISPATCH_LATENCY  = 30 SECONDS,
      MAX_EVENT_SIZE        = 0 KB,
      TRACK_CAUSALITY       = OFF,
      STARTUP_STATE         = ON
    );
     
    ALTER EVENT SESSION FileSizeChanges ON SERVER STATE = START;';
     
    EXEC sys.sp_executesql @sql;

    証拠はプリンにあります

    イベントをデフォルトのトレースに記録するもので意図的に重い模擬ワークロードを作成し、デフォルトのトレースを有効にした場合と無効にした場合で複数回実行して、オブザーバー効果がワークロードに影響を与える可能性があることを示しました。

    SELECT [starting] = sysdatetime();
    GO
     
    EXEC sys.sp_executesql N'CREATE OR ALTER PROCEDURE dbo.dostuff
    AS
    BEGIN
      SET NOCOUNT ON;
      SELECT DISTINCT TOP (1000) object_id, column_id INTO #blat FROM sys.all_columns;
      ALTER TABLE #blat ADD CONSTRAINT PK_wahoo PRIMARY KEY (object_id, column_id);
      ALTER TABLE #blat ADD CONSTRAINT DF_what DEFAULT(1) FOR object_id;
      CREATE INDEX IX_what ON #blat(column_id);
      DROP TABLE #blat;
    END';
     
    EXEC dbo.dostuff;
     
    CREATE USER smidgen WITHOUT LOGIN;
     
    ALTER ROLE db_owner ADD MEMBER smidgen;
     
    DBCC TRACEON(2861) WITH NO_INFOMSGS;
    DBCC TRACEOFF(2861) WITH NO_INFOMSGS;
     
    DROP USER smidgen;
    GO 5000
     
    SELECT [finished] = sysdatetime();
    GO

    平均実行時間:

    デフォルトのトレース
    平均ワークロード時間
    有効 147.4s
    無効 131.6s

    10〜11%の実行時間の短縮は、単独では確かに大きなものではありませんが、200台以上のサーバーのフリート全体にわたる累積的な影響を考えると大きなメリットです。

    次は何ですか?

    まだこれを行わないでください 。デフォルトのトレースを無効にすることのいくつかの副作用について話し合い、ユーザーがXQueryの専門家になることなくセッションデータを簡単に利用できるようにビューを作成する必要があります。しばらくお待ちください!

    [パート1|パート2|パート3]


    1. Word、Excel、PowerPointでのキーボードのみのナビゲーションの使用(パート2:ダイアログボックス)

    2. MySQLの同じテーブルに挿入する方法は?

    3. ASP.NETはSqlConnectionを使用してMySQLを接続します

    4. MySQL-挿入エラーを無視します:重複エントリ