Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Xóa dấu vết mặc định - Phần 2

[Phần 1 | Phần 2 | Phần 3]

Trong bài đầu tiên của loạt bài này, tôi đã trình bày phân tích mà tôi đã sử dụng để xác định rằng dấu vết mặc định không dành cho chúng ta. Trong khi xem xét thông tin mà chúng tôi thực sự cần để thu thập ở vị trí của nó (thay đổi kích thước tệp) và cách thông tin này sẽ được hiển thị cho người dùng, tôi đã xem xét các điểm sau về dấu vết mặc định:

  • nó chỉ chụp tự động sự kiện;
  • nó không nắm bắt được lô "thủ phạm" đã gây ra sự kiện, trừ khi bạn đủ may mắn vì nó cũng bị bắt vì một lý do khác (ví dụ:DDL); và,
  • nó nắm bắt các sự kiện sử dụng giờ địa phương (máy chủ của chúng tôi là miền Đông và tuân theo DST).

Để phòng thủ, nó nắm bắt được rất nhiều thông tin quan trọng về các sự kiện tự động đó. Sau khi chúng tôi vô hiệu hóa theo dõi mặc định, chúng tôi có thể vẫn muốn xem lại các sự kiện đã xảy ra trước khi thay đổi và được ghi lại trong các tệp đó. Nhưng khi dấu vết mặc định bị tắt, hàng không còn tồn tại trong sys.traces , vì vậy bạn không thể xác định đường dẫn đến .trc các tệp từ đó. Đây là nơi mà tính không linh hoạt của dấu vết mặc định thực sự mang lại lợi ích:các tệp được mã hóa cứng để nằm trong cùng một thư mục với SERVERPROPERTY(N'ErrorLogFileName') . Vì vậy, ngay cả khi dấu vết mặc định bị tắt, chúng tôi vẫn có thể lấy dữ liệu từ các tệp bằng cách sử dụng truy vấn sau (với các điều chỉnh để hiển thị dữ liệu trong 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;

Kết quả mẫu từ một máy chủ, nơi chắc chắn có một số sự kiện thủ công và tự động đã xảy ra (nhấp để phóng to):

Viết thay thế

Phiên Sự kiện mở rộng mà tôi đã xây dựng để thay thế phiên này, cũng sẽ ghi lại các thay đổi kích thước tệp thủ công và văn bản truy vấn gây ra các sự kiện tự động, như sau:

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;

Mặc dù nó giống như usernameserver_principal_name có thể là thừa, tôi thực sự đã tìm thấy các trường hợp sau đó là NULL (và có vẻ như vấn đề này đã tồn tại được một thời gian).

Kiểm tra kết quả

Tôi đã bật phiên đó vào ngày 22 tháng 2, do đó, phiên này thiếu các sự kiện mà theo dõi mặc định đã ghi lại vào ngày 12, nhưng nó đã nắm bắt nhiều hơn sự kiện tự động phát triển duy nhất từ ​​ngày 23. Tôi đã chạy truy vấn sau để nhận được kết quả có cùng hình dạng như trên:

;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;

Kết quả cho thấy sự thú vị bổ sung mà tôi đã có, bao gồm (thở hổn hển!) Khi chạy tác vụ "Thu hẹp cơ sở dữ liệu" từ giao diện người dùng (nhấp để phóng to):

Triển khai nó ở mọi nơi

Tự tin rằng giờ đây tôi có thể có được bức tranh hoàn chỉnh hơn về các sự kiện thay đổi kích thước tệp trên bất kỳ máy chủ nào, đã đến lúc triển khai. Tôi đã sử dụng cửa sổ truy vấn CMS để trước tiên vô hiệu hóa theo dõi mặc định ở mọi nơi và đặt show advanced options trở lại như cách tôi đã tìm thấy nó:

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

Sau đó, để tạo phiên Sự kiện mở rộng, tôi cần sử dụng SQL động, vì một số máy chủ có thể có các đường dẫn khác nhau cho SERVERPROPERTY(N'ErrorLogFileName') và đối số đó không thể được tham số hóa.

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;

Bằng chứng nằm trong bánh pudding

Tôi đã tạo một khối lượng công việc giả có chủ ý nặng với những thứ sẽ ghi các sự kiện vào dấu vết mặc định, sau đó chạy nó nhiều lần có và không bật dấu vết mặc định, để cho thấy rằng hiệu ứng người quan sát có thể có tác động đến khối lượng công việc.

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

Thời gian chạy trung bình:

Dấu vết mặc định Thời gian khối lượng công việc trung bình
Đã bật 147,4 giây
Đã tắt 131,6 giây

Việc giảm 10-11% thời gian chạy chắc chắn không phải là quá lớn, nhưng đó là một chiến thắng lớn nếu bạn nghĩ về tác động tích lũy trên toàn bộ nhóm hơn 200 máy chủ.

Tiếp theo là gì?

Chưa làm điều này . Chúng ta vẫn phải nói về một số tác dụng phụ của việc vô hiệu hóa theo dõi mặc định và tạo chế độ xem để người dùng có thể dễ dàng sử dụng dữ liệu phiên mà không cần trở thành chuyên gia XQuery. Hãy theo dõi!

[Phần 1 | Phần 2 | Phần 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. Làm thế nào để tạo cơ sở dữ liệu trong SQL?

  2. SQL là gì?

  3. Giám sát Nhật ký Giao dịch

  4. SQL WHERE Nhiều điều kiện

  5. Hiểu về triển khai Amazon Auroras Multi-AZ