ข้อมูลเหตุการณ์ใดที่ฉันจะได้รับจากค่าเริ่มต้นจาก SQL Server


60

ฉันมักจะเห็นคำถามที่ผู้คนต้องการทราบว่ามีบางสิ่งเกิดขึ้นหรือเมื่อมันเกิดขึ้นหรือใครเป็นผู้ดำเนินการ ในหลายกรณี SQL Server ไม่ได้ติดตามข้อมูลนี้ด้วยตัวเอง ตัวอย่างเช่น:

  • ใครดำเนินการที่ผ่านขั้นตอนการเก็บdbo.MyProcedure?
  • ใครเป็นผู้ปรับปรุงsalaryคอลัมน์ในdbo.Employeesตาราง
  • ใครสอบถามdbo.Ordersตารางล่าสุดจาก Management Studio บ้าง

แต่มีเหตุการณ์อื่น ๆ หลายอย่างที่ SQL Server ที่ไม่ติดตามชั่วคราวโดยค่าเริ่มต้นและกำเนิดสามารถตอบคำถามเกี่ยวกับเช่น:

  • ครั้งสุดท้ายที่การเติบโตอัตโนมัติเกิดขึ้นในฐานข้อมูล AdventureWorks และใช้เวลานานเท่าใด
  • ใครลบdbo.EmployeeAuditDataตารางและเวลา
  • วันนี้มีข้อผิดพลาดเกี่ยวกับหน่วยความจำกี่ข้อ?

ฉันจะรับข้อมูลนี้ได้อย่างไรและจะมีอยู่นานเท่าใด

คำตอบ:


65

มีข้อมูลที่มีค่าค่อนข้างน้อยที่ SQL Server ติดตามให้คุณตามค่าเริ่มต้น ตั้งแต่ SQL Server 2005 ได้มีการ "ร่องรอยเริ่มต้น" ที่ทำงานในพื้นหลังและตั้งแต่ SQL Server 2008 system_healthได้มีการขยายกิจกรรมเซสชั่นทำงานโดยอัตโนมัติที่เรียกว่า

นอกจากนี้คุณยังสามารถค้นหาข้อมูลบางอย่างจากบันทึกข้อผิดพลาดของ SQL Server, บันทึกตัวแทนของเซิร์ฟเวอร์ SQL, บันทึกเหตุการณ์ของ Windows, และบันทึกเพิ่มเติมจากสิ่งต่าง ๆ เช่นการตรวจสอบเซิร์ฟเวอร์ SQL , คลังข้อมูลการจัดการ , การแจ้งเตือนเหตุการณ์ , ทริกเกอร์ DML , ทริกเกอร์ DDL , SCOM / System Centerการติดตามฝั่งเซิร์ฟเวอร์ของคุณหรือเซสชันเพิ่มเติมของเหตุการณ์หรือโซลูชันการตรวจสอบบุคคลที่สาม (เช่นที่ทำโดยSQL Sentry ของนายจ้างของฉัน ) นอกจากนี้คุณยังสามารถเลือกที่จะเปิดใช้งานที่เรียกว่า "Blackbox ร่องรอย" เพื่อช่วยในการแก้ไขปัญหา

แต่สำหรับโพสต์นี้ฉันจะเน้นขอบเขตของสิ่งที่เปิดใช้งานได้ทุกที่มากที่สุด: การติดตามเริ่มต้น, เซสชันการขยายกิจกรรมและบันทึกข้อผิดพลาด

การติดตามเริ่มต้น

ร่องรอยเริ่มต้นมักจะทำงานบนระบบส่วนใหญ่จนกว่าคุณจะได้ปิดการใช้งานได้โดยใช้ sp_configureตราบใดที่มีการเปิดใช้งานสิ่งนี้อาจเป็นแหล่งข้อมูลที่มีค่ามากมาย รายการต่อไปนี้แสดงเหตุการณ์การติดตามที่ถูกจับ:

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;

คุณสามารถดูรายละเอียดเพิ่มเติมได้โดยเข้าร่วมเพื่อsys.trace_columnsดูว่าเหตุการณ์ใดมาพร้อมกับข้อมูลใด แต่ตอนนี้ฉันจะข้ามไปเนื่องจากคุณสามารถเห็นสิ่งที่คุณมีเมื่อคุณสอบถามข้อมูลการติดตามสำหรับเหตุการณ์เฉพาะ สิ่งเหล่านี้เป็นเหตุการณ์ที่มีอยู่ในระบบของฉัน (คุณควรเรียกใช้แบบสอบถามกับคุณเพื่อให้แน่ใจว่าตรงกันแม้ว่าจะยังคงเป็นชุดของเหตุการณ์เดียวกันผ่าน 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

โปรดทราบว่าการติดตามเริ่มต้นใช้ไฟล์แบบโรลโอเวอร์ดังนั้นข้อมูลที่มีให้คุณจะย้อนกลับไปจนถึงช่วงวันที่ของข้อมูลที่มีอยู่จะขึ้นอยู่กับจำนวนเหตุการณ์ข้างต้นที่จะถูกบันทึกและความถี่ใด หากคุณต้องการให้แน่ใจว่าคุณเก็บประวัติไว้ได้นานขึ้นคุณสามารถตั้งค่างานที่เก็บถาวรไฟล์ที่ไม่ได้ใช้งานในปัจจุบันซึ่งเชื่อมโยงกับการติดตามเป็นระยะ

ตัวอย่าง

ในคำถามฉันถามคำถามสองสามข้อที่ฉันพบ นี่คือตัวอย่างแบบสอบถามสำหรับการดึงข้อมูลเฉพาะจากการติดตามเริ่มต้น

คำถาม: ครั้งสุดท้ายที่การเติบโตอัตโนมัติเกิดขึ้นในฐานข้อมูล AdventureWorks และใช้เวลานานเท่าใด

แบบสอบถามนี้จะดึงเหตุการณ์ AutoGrow ทั้งหมดในฐานข้อมูล AdventureWorks สำหรับไฟล์บันทึกและข้อมูลที่ยังคงอยู่ในไฟล์บันทึกการติดตามเริ่มต้น:

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;

คำถาม: ใครลบตาราง dbo.EmployeeAuditData และเมื่อใด

นี้จะกลับใด ๆเหตุการณ์ที่เกิดขึ้นสำหรับวัตถุที่มีชื่อว่าDROP EmployeeAuditDataหากคุณต้องการตรวจสอบให้แน่ใจว่ามันตรวจพบDROPเหตุการณ์สำหรับตารางเท่านั้นคุณสามารถเพิ่มตัวกรอง: ObjectType = 8277( รายการแบบเต็มมีการบันทึกไว้ที่นี่ ) หากคุณต้องการที่จะ จำกัด 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;

มีภาวะแทรกซ้อนที่นี่และมันเป็นกรณีที่ขอบมาก แต่คิดว่ามันรอบคอบที่จะพูดถึงต่อไป หากคุณใช้สกีมาหลายรายการและอาจมีชื่อวัตถุเดียวกันในหลายสกีมาคุณจะไม่สามารถบอกได้ว่าอันนี้คืออะไร (เว้นแต่มีอยู่) มีกรณีภายนอกที่ UserA อาจลบ SchemaB.Tablename ในขณะที่ UserB อาจทิ้ง SchemaA.Tablename การติดตามเริ่มต้นไม่ได้ติดตามสคีมาของวัตถุ (หรือไม่จับภาพTextDataสำหรับเหตุการณ์นี้) และObjectIDรวมอยู่ในการติดตามไม่เป็นประโยชน์สำหรับการจับคู่โดยตรง (เพราะวัตถุถูกทิ้งและไม่มีอยู่อีกต่อไป) การรวมคอลัมน์นั้นในผลลัพธ์ในกรณีนี้อาจเป็นประโยชน์ในการอ้างอิงโยงกับสำเนาใด ๆ ของตารางที่มีชื่อเดียวกันกับที่ยังคงมีอยู่ แต่หากระบบอยู่ในความระส่ำระสายนี้มาก (หรือหากสำเนาดังกล่าวทั้งหมดถูกลบ) ที่นั่น ยังคงอาจไม่ใช่วิธีที่เชื่อถือได้ในการเดาว่าใครเป็นผู้คัดลอกตาราง

เหตุการณ์เพิ่มเติม

จากการสนับสนุน SQL Server 2008: เซสชัน system_health (SQLCSS Blog)ต่อไปนี้เป็นรายการข้อมูลที่คุณสามารถคัดออกจากsystem_healthเซสชันใน SQL Server 2008 และ 2008 R2:

  • sql_text และ session_id สำหรับเซสชันใด ๆ ที่พบข้อผิดพลาดที่มีความรุนแรง> = 20
  • sql_text และ session_id สำหรับเซสชันใด ๆ ที่พบข้อผิดพลาดประเภท "หน่วยความจำ" เช่น 17803, 701 ฯลฯ (เราเพิ่มสิ่งนี้เพราะไม่ใช่ข้อผิดพลาดของหน่วยความจำทั้งหมดจะรุนแรง> = 20)
  • บันทึกปัญหา "ที่ไม่ยอมทำ" (บางครั้งคุณเคยเห็นสิ่งเหล่านี้ใน ERRORLOG เป็นข่าวสารเกี่ยวกับ 17883)
  • การหยุดชะงักใด ๆ ที่ตรวจพบ
  • callstack, sql_text และ session_id สำหรับเซสชันใด ๆ ที่รอการรอ (หรือทรัพยากรที่น่าสนใจอื่น ๆ ) เป็นเวลา> 15 วินาที
  • callstack, sql_text และ session_id สำหรับเซสชันใด ๆ ที่รอการล็อคเป็นเวลา> 30 วินาที
  • callstack, sql_text และ session_id สำหรับเซสชันใด ๆ ที่รอเป็นระยะเวลานานสำหรับการรอ "ภายนอก" หรือ "รอการจองล่วงหน้า"

จากใช้เซสชันเหตุการณ์ system_health (MSDN)รายการจะถูกขยายใน SQL Server 2012 (และยังคงเหมือนเดิมสำหรับ SQL Server 2014):

  • sql_text และ session_id สำหรับเซสชันใด ๆ ที่พบข้อผิดพลาดที่มีความรุนแรง> = 20
  • sql_text และ session_id สำหรับเซสชันใด ๆ ที่พบข้อผิดพลาดเกี่ยวกับหน่วยความจำ ข้อผิดพลาด ได้แก่ 17803, 701, 802, 8645, 8651, 8657 และ 8902
  • บันทึกปัญหาตัวจัดกำหนดการที่ไม่ได้ผล (สิ่งเหล่านี้ปรากฏในบันทึกข้อผิดพลาด SQL Server เป็นข้อผิดพลาด 17883)
  • การหยุดชะงักใด ๆ ที่ตรวจพบ
  • callstack, sql_text และ session_id สำหรับเซสชันใด ๆ ที่รออยู่กับแลตช์ (หรือทรัพยากรที่น่าสนใจอื่น ๆ ) เป็นเวลา> 15 วินาที
  • callstack, sql_text และ session_id สำหรับเซสชันใด ๆ ที่รอการล็อคเป็นเวลา> 30 วินาที
  • callstack, sql_text และ session_id สำหรับเซสชันใด ๆ ที่รอมาเป็นเวลานานสำหรับการจองล่วงหน้า ระยะเวลาแตกต่างกันไปตามประเภทการรอ การรอคอยแบบ preemptive คือที่ซึ่งเซิร์ฟเวอร์ SQL กำลังรอการเรียก API ภายนอก
  • callstack และ session_id สำหรับการจัดสรร CLR และการจัดสรรเสมือนล้มเหลว
  • เหตุการณ์ ring_buffer สำหรับนายหน้าหน่วยความจำมอนิเตอร์ตัวกำหนดตารางเวลาโหนดโหนด OOM ความปลอดภัยและการเชื่อมต่อ
  • ส่วนประกอบของระบบเป็นผลมาจาก sp_server_diagnostics
  • สถานะอินสแตนซ์ที่รวบรวมโดย scheduler_monitor_system_health_ring_buffer_recorded
  • การจัดสรร CLR ล้มเหลว
  • ข้อผิดพลาดการเชื่อมต่อโดยใช้ connection_ring_buffer_recorded
  • ข้อผิดพลาดด้านความปลอดภัยโดยใช้ security_error_ring_buffer_recorded

ใน SQL Server 2016 จะมีการจับภาพอีกสองเหตุการณ์:

  • เมื่อกระบวนการถูกฆ่าโดยใช้KILLคำสั่ง
  • เมื่อการปิด SQL Server เริ่มขึ้น

(เอกสารยังไม่ได้รับการปรับปรุงแต่ฉัน blogged เกี่ยวกับวิธีที่ฉันค้นพบการเปลี่ยนแปลงเหล่านี้และอื่น ๆ )

หากต้องการรับการกำหนดค่าที่มีความลับเพิ่มเติมที่ใช้กับเวอร์ชันเฉพาะของคุณคุณสามารถเรียกใช้คิวรีต่อไปนี้ได้โดยตรง แต่คุณจะต้องแปลชื่อและแยกเพรดิเคตให้ตรงกับรายการภาษาที่เป็นธรรมชาติด้านบน:

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;

หากคุณกำลังใช้กลุ่มความพร้อมใช้งานนอกจากนี้ยังมีสองช่วงใหม่ที่คุณจะได้พบกับการทำงาน: และAlwaysOn_failover AlwaysOn_healthคุณสามารถดูข้อมูลที่พวกเขารวบรวมด้วยแบบสอบถามต่อไปนี้:

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;

เซสชันกิจกรรมเหล่านี้ใช้เป้าหมายบัฟเฟอร์บัฟเฟอร์เพื่อเก็บข้อมูลเช่นพูลบัฟเฟอร์และแคชแผนกิจกรรมที่เก่ากว่าจะเลิกใช้ดังนั้นคุณจะไม่สามารถดึงกิจกรรมจากช่วงวันที่ที่คุณต้องการได้

ตัวอย่าง

ในคำถามที่ฉันโพสต์คำถามที่สมมติขึ้นนี้:

วันนี้มีข้อผิดพลาดเกี่ยวกับหน่วยความจำกี่ข้อ?

นี่คือตัวอย่างแบบสอบถาม (และอาจไม่มีประสิทธิภาพมาก) ที่สามารถดึงข้อมูลนี้จากsystem_healthเซสชัน:

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

(ตัวอย่างนี้ยืมมาจากบล็อกโพสต์เบื้องต้นของ Amit Banerjee ในsystem_healthเซสชั่น )

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ Extended Events (รวมถึงตัวอย่างมากมายที่คุณสามารถค้นหาข้อมูลที่เฉพาะเจาะจง) ดูชุดบล็อก 31 ส่วนโดย Jonathan Kehayias:

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

บันทึกข้อผิดพลาด

โดยค่าเริ่มต้น SQL Server จะเก็บไฟล์บันทึกข้อผิดพลาดล่าสุดรวม 6 ครั้งล่าสุด (แต่คุณสามารถเปลี่ยนแปลงได้ ) ข้อมูลจำนวนมากถูกเก็บไว้ที่นั่นรวมถึงข้อมูลการเริ่มต้น (จำนวนคอร์ที่ใช้งานไม่ว่าจะเป็นการตั้งค่าหน้าล็อคในหน่วยความจำโหมดการพิสูจน์ตัวตน ฯลฯ ) รวมถึงข้อผิดพลาดและสถานการณ์อื่น ๆ ที่รุนแรงพอที่จะบันทึกไว้ ตัวอย่างล่าสุดหนึ่งคือคนที่กำลังค้นหาเมื่อฐานข้อมูลถูกออฟไลน์ คุณสามารถตรวจสอบสิ่งนี้ได้โดยการสแกนบันทึกข้อผิดพลาดล่าสุด 7 รายการสำหรับข้อความ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';

ฉันครอบคลุมรายละเอียดอื่น ๆ บางส่วนในคำตอบที่ผ่านมานี้และนอกจากนี้ยังมีข้อมูลพื้นฐานบางอย่างที่ดีที่ toadworldและในเอกสารอย่างเป็นทางการ

กลุ่มหนึ่งของ "ข้อผิดพลาด" บันทึกข้อผิดพลาดจะติดตามโดยค่าเริ่มต้น - และสามารถทำให้ข้อมูลที่สำคัญหลุดออกจากหางได้เร็วกว่ามาก - คือทุกข้อความสำรองที่ประสบความสำเร็จ คุณสามารถป้องกันเหล่านี้จากการเติมขึ้นบันทึกข้อผิดพลาดที่มีสัญญาณรบกวนโดยการเปิดใช้งานการติดตามธง 3226

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.