Thông tin sự kiện nào tôi có thể nhận được theo mặc định từ SQL Server?


60

Tôi thường thấy những câu hỏi mà mọi người muốn biết nếu một điều gì đó xảy ra, hoặc khi nó xảy ra, hoặc ai đã thực hiện hành động. Trong rất nhiều trường hợp, SQL Server không tự mình theo dõi thông tin này. Ví dụ:

  • Ai thực hiện thủ tục lưu trữ cuối cùng dbo.MyProcedure?
  • Ai cập nhật salarycột trong dbo.Employeesbảng?
  • Ai cuối cùng đã truy vấn dbo.Ordersbảng từ Management Studio?

Nhưng có một số sự kiện khác SQL Server không theo dõi tạm thời theo mặc định và tự nhiên có thể trả lời câu hỏi về, chẳng hạn như:

  • Lần cuối cùng xảy ra tự động phát triển trong cơ sở dữ liệu AdventureWorks là bao lâu và mất bao lâu?
  • Ai đã xóa dbo.EmployeeAuditDatabảng và khi nào?
  • Có bao nhiêu lỗi liên quan đến bộ nhớ đã xảy ra ngày hôm nay?

Làm thế nào để tôi có được thông tin này, và nó có sẵn trong bao lâu?

Câu trả lời:


65

Theo mặc định, có khá nhiều thông tin có giá trị mà SQL Server theo dõi cho bạn. Vì SQL Server 2005 đã có một "dấu vết mặc định" chạy trong nền và vì SQL Server 2008 đã có một phiên Sự kiện mở rộng tự động chạy, được gọi system_health.

Bạn cũng có thể tìm thấy một số thông tin nhất định từ nhật ký lỗi Máy chủ SQL, Nhật ký tác nhân máy chủ SQL, nhật ký sự kiện Windows và ghi nhật ký bổ sung từ những thứ như Kiểm toán máy chủ SQL , Kho dữ liệu quản lý , Thông báo sự kiện , Kích hoạt DML , Kích hoạt DDL , SCOM / Trung tâm hệ thống , dấu vết phía máy chủ của riêng bạn hoặc các phiên Sự kiện mở rộng hoặc giải pháp giám sát của bên thứ ba (giống như các giải pháp được tạo bởi chủ nhân của tôi, SQL Sentry ). Bạn cũng có thể tùy chọn kích hoạt cái gọi là "Dấu vết hộp đen" để hỗ trợ khắc phục sự cố .

Nhưng đối với bài đăng này, tôi sẽ tập trung vào phạm vi vào những thứ thường được kích hoạt ở mọi nơi: theo dõi mặc định, các phiên Sự kiện mở rộng và nhật ký lỗi.

Dấu vết mặc định

Theo dõi mặc định thường chạy trên hầu hết các hệ thống, trừ khi bạn đã tắt nó bằng cách sử dụngsp_configure . Miễn là nó được kích hoạt, đây có thể là một nguồn thông tin có giá trị phong phú. Sau đây liệt kê các sự kiện theo dõi được ghi lại:

DECLARE @TraceID INT;

SELECT @TraceID = id FROM sys.traces WHERE is_default = 1;

SELECT t.EventID, e.name as Event_Description
  FROM sys.fn_trace_geteventinfo(@TraceID) t
  JOIN sys.trace_events e ON t.eventID = e.trace_event_id
  GROUP BY t.EventID, e.name;

Bạn có thể biết chi tiết hơn bằng cách tham gia để sys.trace_columnsxem sự kiện nào đi kèm với dữ liệu nào, nhưng bây giờ tôi sẽ bỏ qua điều đó, vì bạn có thể thấy những gì bạn có khi bạn thực sự truy vấn dữ liệu theo dõi cho các sự kiện cụ thể. Đây là những sự kiện có sẵn trên hệ thống của tôi (bạn nên chạy truy vấn trên máy của bạn để chắc chắn chúng phù hợp, mặc dù đây vẫn là cùng một sự kiện thông qua SQL Server 2019 CTP 2.4):

EventID  Event_Description
-------  ----------------------------------------------
18       Audit Server Starts And Stops
20       Audit Login Failed
22       ErrorLog
46       Object:Created
47       Object:Deleted
55       Hash Warning
69       Sort Warnings
79       Missing Column Statistics
80       Missing Join Predicate
81       Server Memory Change
92       Data File Auto Grow
93       Log File Auto Grow
94       Data File Auto Shrink
95       Log File Auto Shrink
102      Audit Database Scope GDR Event
103      Audit Schema Object GDR Event
104      Audit Addlogin Event
105      Audit Login GDR Event
106      Audit Login Change Property Event
108      Audit Add Login to Server Role Event
109      Audit Add DB User Event
110      Audit Add Member to DB Role Event
111      Audit Add Role Event
115      Audit Backup/Restore Event
116      Audit DBCC Event
117      Audit Change Audit Event
152      Audit Change Database Owner
153      Audit Schema Object Take Ownership Event
155      FT:Crawl Started
156      FT:Crawl Stopped
164      Object:Altered
167      Database Mirroring State Change
175      Audit Server Alter Trace Event
218      Plan Guide Unsuccessful

Lưu ý rằng theo dõi mặc định sử dụng các tệp cuộn qua và do đó, dữ liệu có sẵn cho bạn sẽ chỉ quay trở lại cho đến nay - phạm vi ngày của dữ liệu có sẵn tùy thuộc vào số lượng sự kiện trên được ghi lại và ở tần số nào. Nếu bạn muốn đảm bảo rằng bạn giữ một lịch sử lâu hơn, bạn có thể thiết lập một công việc lưu trữ định kỳ các tệp hiện không hoạt động được liên kết với dấu vết.

Ví dụ

Trong câu hỏi tôi đã hỏi một vài câu hỏi mà tôi đã tìm thấy. Dưới đây là các truy vấn ví dụ để lấy thông tin cụ thể đó từ dấu vết mặc định.

Câu hỏi: Lần cuối cùng xảy ra tự động phát triển trong cơ sở dữ liệu AdventureWorks là khi nào và mất bao lâu?

Truy vấn này sẽ kéo tất cả các sự kiện AutoGrow trong cơ sở dữ liệu AdventureWorks, cho cả tệp nhật ký và dữ liệu, vẫn còn trong tệp nhật ký theo dõi mặc định:

DECLARE @path NVARCHAR(260);

SELECT 
   @path = REVERSE(SUBSTRING(REVERSE([path]), 
   CHARINDEX(CHAR(92), REVERSE([path])), 260)) + N'log.trc'
FROM    sys.traces
WHERE   is_default = 1;

SELECT 
   DatabaseName,
   [FileName],
   SPID,
   Duration,
   StartTime,
   EndTime,
   FileType = CASE EventClass WHEN 92 THEN 'Data' ELSE 'Log' END
FROM sys.fn_trace_gettable(@path, DEFAULT)
WHERE EventClass IN (92,93)
AND DatabaseName = N'AdventureWorks'
ORDER BY StartTime DESC;

Câu hỏi: Ai đã xóa bảng dbo.EmployeeAuditData và khi nào?

Điều này sẽ trả về bất kỳ DROPsự kiện cho một đối tượng được đặt tên EmployeeAuditData. Nếu bạn muốn đảm bảo rằng nó chỉ phát hiện DROPcác sự kiện cho các bảng, bạn có thể thêm bộ lọc: ObjectType = 8277( danh sách đầy đủ được ghi lại ở đây ). Nếu bạn muốn giới hạn không gian tìm kiếm vào một cơ sở dữ liệu cụ thể, bạn có thể thêm bộ lọc : DatabaseName = N'db_name'.

DECLARE @path NVARCHAR(260);

SELECT 
   @path = REVERSE(SUBSTRING(REVERSE([path]), 
   CHARINDEX(CHAR(92), REVERSE([path])), 260)) + N'log.trc'
FROM    sys.traces
WHERE   is_default = 1;

SELECT 
  LoginName,
  HostName,
  StartTime,
  ObjectName,
  TextData
FROM sys.fn_trace_gettable(@path, DEFAULT)
WHERE EventClass = 47    -- Object:Deleted
AND EventSubClass = 1
AND ObjectName = N'EmployeeAuditData'
ORDER BY StartTime DESC;

Có một sự phức tạp ở đây, và nó là trường hợp rất cạnh nhưng nghĩ rằng nó thận trọng để đề cập đến dù sao. Nếu bạn sử dụng nhiều lược đồ và có thể có cùng tên đối tượng trong nhiều lược đồ, bạn sẽ không thể biết đây là lược đồ nào (trừ khi đối tác của nó vẫn tồn tại). Có một trường hợp bên ngoài rằng UserA có thể đã bỏ SchemaB.Tablename trong khi UserB có thể đã bỏ SchemaA.Tablename. Theo dõi mặc định không theo dõi lược đồ của đối tượng (cũng không chụp TextDatacho sự kiện này) vàObjectIDbao gồm trong theo dõi là không hữu ích cho một trận đấu trực tiếp (vì đối tượng đã bị loại bỏ và không còn tồn tại). Bao gồm cột đó trong đầu ra trong trường hợp này có thể hữu ích để tham chiếu chéo với bất kỳ bản sao nào của bảng có cùng tên vẫn tồn tại, nhưng nếu hệ thống ở trong tình trạng hỗn loạn này (hoặc nếu tất cả các bản sao đó đã bị xóa) ở đó vẫn có thể không phải là một cách đáng tin cậy để đoán xem bản sao của bảng bị bỏ bởi ai.

Sự kiện mở rộng

Từ Hỗ trợ SQL Server 2008: Phiên system_health (Blog SQLCSS) , sau đây là danh sách dữ liệu bạn có thể loại bỏ từ system_healthphiên trong SQL Server 2008 và 2008 R2:

  • Sql lòng và session_id cho bất kỳ phiên nào gặp lỗi với mức độ nghiêm trọng> = 20
  • Sql lòng và session_id cho bất kỳ phiên nào gặp phải loại lỗi "bộ nhớ", chẳng hạn như 17804, 701, v.v. (chúng tôi đã thêm điều này vì không phải tất cả các lỗi bộ nhớ đều nghiêm trọng> = 20)
  • Một hồ sơ về bất kỳ vấn đề "không mang lại lợi nhuận" nào (đôi khi bạn đã thấy những vấn đề này trong ERRORLOG là Msg 17883)
  • Bất kỳ sự bế tắc được phát hiện
  • Callstack, sql lòng và session_id cho bất kỳ phiên nào đã chờ trên chốt (hoặc các tài nguyên thú vị khác) trong> 15 giây
  • Callstack, sql lòng và session_id cho bất kỳ phiên nào đã chờ khóa trong> 30 giây
  • Callstack, sql lòng và session_id cho bất kỳ phiên nào đã chờ trong một khoảng thời gian dài cho các chờ đợi "bên ngoài" hoặc "chờ đợi trước".

Từ Sử dụng phiên sự kiện system_health (MSDN) , danh sách được mở rộng phần nào trong SQL Server 2012 (và vẫn giữ nguyên cho SQL Server 2014):

  • S sql lòng và session_id cho bất kỳ phiên nào gặp lỗi có mức độ nghiêm trọng> = 20.
  • S sql lòng và session_id cho bất kỳ phiên nào gặp lỗi liên quan đến bộ nhớ. Các lỗi bao gồm 17804, 701, 802, 8645, 8651, 8657 và 8902.
  • Một hồ sơ của bất kỳ vấn đề lịch trình không năng suất. (Chúng xuất hiện trong nhật ký lỗi Máy chủ SQL là lỗi 17883.)
  • Bất kỳ bế tắc được phát hiện.
  • Callstack, sql lòng và session_id cho bất kỳ phiên nào đã chờ trên chốt (hoặc các tài nguyên thú vị khác) trong> 15 giây.
  • Callstack, sql lòng và session_id cho bất kỳ phiên nào đã chờ trên khóa trong> 30 giây.
  • Callstack, sql lòng và session_id cho bất kỳ phiên nào đã chờ đợi trong một thời gian dài để chờ đợi ưu tiên. Thời lượng thay đổi theo loại chờ. Chờ đợi ưu tiên là nơi SQL Server đang chờ các cuộc gọi API bên ngoài.
  • Callstack và session_id cho phân bổ CLR và thất bại phân bổ ảo.
  • Các sự kiện ring_buffer cho trình môi giới bộ nhớ, trình theo dõi lịch trình, OOM nút bộ nhớ, bảo mật và kết nối.
  • Kết quả thành phần hệ thống từ sp_server_diagnostics.
  • Sức khỏe sơ thẩm được thu thập bởi calendaruler_monitor_system_health_ring_buffer_recorded.
  • Thất bại phân bổ CLR.
  • Lỗi kết nối bằng cách sử dụng Connection_ring_buffer_recorded.
  • Lỗi bảo mật khi sử dụng security_error_ring_buffer_recorded.

Trong SQL Server 2016, hai sự kiện nữa được ghi lại:

  • Khi một quá trình bị giết bằng KILLlệnh.
  • Khi tắt máy chủ SQL đã được bắt đầu.

(Tài liệu chưa được cập nhật, nhưng tôi viết blog về cách tôi khám phá những điều này và những thay đổi khác .)

Để có được cấu hình khó hiểu hơn áp dụng cho phiên bản cụ thể của bạn, bạn luôn có thể chạy truy vấn sau trực tiếp, nhưng bạn sẽ phải giải thích tên và phân tích các vị từ để khớp với danh sách ngôn ngữ tự nhiên hơn ở trên:

SELECT e.package, e.event_id, e.name, e.predicate
  FROM sys.server_event_session_events AS e
  INNER JOIN sys.server_event_sessions AS s
  ON e.event_session_id = s.event_session_id
 WHERE s.name = N'system_health'
 ORDER BY e.package, e.name;

Nếu bạn đang sử dụng Nhóm sẵn có, cũng có hai phiên mới mà bạn sẽ tìm thấy đang chạy: AlwaysOn_failoverAlwaysOn_health. Bạn có thể xem dữ liệu họ thu thập bằng truy vấn sau:

SELECT s.name, e.package, e.event_id, e.name, e.predicate
  FROM sys.server_event_session_events AS e
  INNER JOIN sys.server_event_sessions AS s
  ON e.event_session_id = s.event_session_id
 WHERE s.name LIKE N'AlwaysOn[_]%'
 ORDER BY s.name, e.package, e.name;

Các phiên sự kiện này sử dụng các mục tiêu bộ đệm vòng để lưu trữ dữ liệu, vì vậy - như nhóm bộ đệm và bộ đệm kế hoạch - các sự kiện cũ hơn sẽ được loại bỏ, do đó bạn không nhất thiết có thể lấy các sự kiện từ phạm vi ngày bạn muốn.

Thí dụ

Trong câu hỏi tôi đặt ra câu hỏi hư cấu này:

Có bao nhiêu lỗi liên quan đến bộ nhớ đã xảy ra ngày hôm nay?

Đây là một truy vấn mẫu (và có thể không hiệu quả lắm) có thể lấy thông tin này từ system_healthphiên:

;WITH src(x) AS
(
  SELECT y.query('.')
  FROM
  (
    SELECT x = CONVERT(XML, t.target_data)
      FROM sys.dm_xe_sessions AS s
      INNER JOIN sys.dm_xe_session_targets AS t
      ON s.[address] = t.event_session_address
      WHERE s.name = N'system_health'
  ) AS x
  CROSS APPLY x.x.nodes('/RingBufferTarget/event') AS y(y)
)
SELECT 
  x, ts = CONVERT(DATETIME, NULL), err = CONVERT(INT, NULL)
INTO #blat FROM src;

DELETE #blat WHERE x.value('(/event/@name)[1]', 'varchar(255)') <> 'error_reported';

UPDATE #blat SET ts = x.value('(/event/@timestamp)[1]', 'datetime');

UPDATE #blat SET err = x.value('(/event/data/value)[1]', 'int');

SELECT err, number_of_events = COUNT(*)
  FROM #blat
  WHERE err IN (17803, 701, 802, 8645, 8651, 8657, 8902)
  AND ts >= CONVERT(DATE, CURRENT_TIMESTAMP)
  GROUP BY err;

DROP TABLE #blat;

(Ví dụ này mượn lỏng lẻo từ bài đăng blog giới thiệu của Amit Banerjee trong system_healthphiên .)

Để biết thêm thông tin về Sự kiện mở rộng (bao gồm nhiều ví dụ nơi bạn có thể truy vấn dữ liệu cụ thể), hãy xem loạt blog gồm 31 phần này của Jonathan Kehayias:

https://www.sqlskills.com/bloss/jonathan/an-xevent-a-day-31-days-of-extends-events/

Nhật ký lỗi

SQL Server theo mặc định giữ hiện tại cộng với 6 tệp nhật ký lỗi gần đây nhất (nhưng bạn có thể thay đổi điều này ). Rất nhiều thông tin được lưu trữ ở đó, bao gồm thông tin khởi động (có bao nhiêu lõi được sử dụng, liệu các trang khóa trong bộ nhớ được đặt, chế độ xác thực, v.v.) cũng như các lỗi và các tình huống khác đủ nghiêm trọng để ghi lại (và không được ghi lại ở nơi khác). Một ví dụ gần đây là ai đó đang tìm kiếm khi cơ sở dữ liệu được thực hiện ngoại tuyến. Bạn có thể xác định điều này bằng cách quét qua từng bản ghi 7 lỗi gần đây nhất cho văn bản Setting database option OFFLINE:

EXEC sys.sp_readerrorlog 0,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 1,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 2,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 3,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 4,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 5,1,'Setting database option OFFLINE';
EXEC sys.sp_readerrorlog 6,1,'Setting database option OFFLINE';

Tôi đã đề cập đến một số chi tiết khác trong câu trả lời gần đây , và cũng có một số thông tin cơ bản tốt tại toadworld và cả trong tài liệu chính thức .

Một nhóm "lỗi" nhật ký lỗi theo dõi theo mặc định - và có thể làm cho thông tin quan trọng rơi ra khỏi đuôi nhanh hơn nhiều - là mỗi thông báo sao lưu thành công. Bạn có thể ngăn những thứ này lấp đầy nhật ký lỗi bằng tiếng ồn bằng cách bật cờ theo dõi 3226 .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.