Informasi acara apa yang bisa saya dapatkan secara default dari SQL Server?

60

Saya sering melihat pertanyaan di mana orang ingin tahu apakah suatu hal terjadi, atau kapan itu terjadi, atau siapa yang melakukan tindakan. Dalam banyak kasus, SQL Server tidak melacak informasi ini sendiri. Sebagai contoh:

  • Siapa yang terakhir menjalankan prosedur tersimpan dbo.MyProcedure?
  • Siapa yang memperbarui salarykolom di dbo.Employeestabel?
  • Siapa yang terakhir menanyakan dbo.Orderstabel dari Management Studio?

Namun ada beberapa peristiwa lain yang SQL Server tidak melacak sementara secara default, dan native dapat menjawab pertanyaan tentang, seperti:

  • Kapan terakhir kali pertumbuhan otomatis terjadi dalam basis data AdventureWorks, dan berapa lama?
  • Siapa yang menghapus dbo.EmployeeAuditDatatabel dan kapan?
  • Berapa banyak kesalahan terkait memori yang terjadi hari ini?

Bagaimana saya mendapatkan informasi ini, dan berapa lama tetap tersedia?

Aaron Bertrand
sumber

Jawaban:

65

Ada sedikit informasi berharga yang secara default dilacak oleh SQL Server. Sejak SQL Server 2005 telah ada "jejak default" yang berjalan di latar belakang, dan sejak SQL Server 2008 telah ada sesi Extended Events yang secara otomatis berjalan, disebut system_health.

Anda juga dapat menemukan informasi tertentu dari log galat SQL Server, log Agen SQL Server, log peristiwa Windows, dan pencatatan tambahan dari hal-hal seperti Audit SQL Server , Gudang Data Manajemen , Pemberitahuan Kejadian , Pemicu DML , Pemicu DDL , Pemicu DDL , Pemicu SCOM / Pusat Sistem , jejak sisi server Anda sendiri atau sesi Acara yang Diperpanjang, atau solusi pemantauan pihak ketiga (seperti yang dibuat oleh majikan saya, SQL Sentry ). Anda juga dapat secara opsional mengaktifkan apa yang disebut "Jejak Blackbox" untuk membantu dalam pemecahan masalah .

Tetapi untuk posting ini saya akan memfokuskan ruang lingkup pada hal-hal yang umumnya paling diaktifkan di mana-mana: jejak default, sesi Acara yang Diperpanjang, dan log kesalahan.

Jejak Bawaan

Jejak default biasanya berjalan di sebagian besar sistem, kecuali jika Anda menonaktifkannya menggunakansp_configure . Selama diaktifkan, ini bisa menjadi sumber informasi berharga yang kaya. Berikut ini daftar acara jejak yang ditangkap:

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;

Anda dapat masuk ke detail lebih lanjut dengan bergabung untuk sys.trace_columnsmelihat acara mana yang datang dengan data mana, tapi saya akan melewatkannya untuk saat ini, karena Anda dapat melihat apa yang Anda miliki ketika Anda benar-benar meminta data jejak untuk peristiwa tertentu. Ini adalah peristiwa yang tersedia di sistem saya (Anda harus menjalankan kueri pada Anda untuk memastikan mereka cocok, meskipun ini masih set peristiwa yang sama melalui 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

Perhatikan bahwa penelusuran default menggunakan file rollover dan data yang tersedia untuk Anda hanya akan kembali sejauh ini - rentang tanggal data yang tersedia tergantung pada berapa banyak peristiwa di atas yang ditangkap dan pada frekuensi berapa. Jika Anda ingin memastikan bahwa Anda memiliki riwayat yang lebih lama, Anda dapat mengatur pekerjaan yang secara berkala mengarsipkan file yang saat ini tidak aktif yang terkait dengan jejak.

Contohnya

Dalam pertanyaan saya mengajukan beberapa pertanyaan yang saya temukan. Berikut adalah contoh kueri untuk menarik informasi tertentu dari jejak default.

Pertanyaan: Kapan terakhir kali pertumbuhan otomatis terjadi di basis data AdventureWorks, dan berapa lama?

Kueri ini akan menarik semua peristiwa AutoGrow di database AdventureWorks, untuk file log dan data, yang masih dalam file log jejak default:

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;

Pertanyaan: Siapa yang menghapus tabel dbo.EmployeeAuditData dan kapan?

Ini akan mengembalikan DROPperistiwa apa pun untuk objek bernama EmployeeAuditData. Jika Anda ingin memastikan bahwa itu hanya mendeteksi DROPacara untuk tabel, Anda dapat menambahkan filter: ObjectType = 8277( daftar lengkapnya didokumentasikan di sini ). Jika Anda ingin membatasi ruang pencarian untuk database tertentu, Anda dapat menambahkan filter: 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;

Ada komplikasi di sini, dan ini adalah kasus yang sangat ujung tetapi berpikir itu bijaksana untuk disebutkan pula. Jika Anda menggunakan beberapa skema dan mungkin memiliki nama objek yang sama di beberapa skema, Anda tidak akan dapat mengetahui yang mana ini (kecuali jika masih ada rekannya). Ada kasus luar bahwa UserA mungkin telah menjatuhkan SchemaB.Tablename sementara UserB mungkin telah menjatuhkan SchemaA.Tablename. Jejak default tidak melacak skema objek (juga tidak menangkap TextDatauntuk acara ini), danObjectIDtermasuk dalam jejak tidak berguna untuk pertandingan langsung (karena objek dijatuhkan dan tidak ada lagi). Termasuk bahwa kolom dalam output dalam hal ini mungkin berguna untuk referensi silang terhadap setiap salinan tabel dengan nama yang sama yang masih ada, tetapi jika sistem dalam banyak kekacauan ini (atau jika semua salinan tersebut telah dihapus) ada masih mungkin bukan cara yang dapat diandalkan untuk menebak di mana salinan tabel dijatuhkan oleh siapa.

Acara yang Diperpanjang

Dari Mendukung SQL Server 2008: Sesi system_health (SQLCSS Blog) , berikut ini adalah daftar data yang dapat Anda ambil dari system_healthsesi di SQL Server 2008 dan 2008 R2:

  • Sql_text dan session_id untuk setiap sesi yang menemukan kesalahan dengan tingkat keparahan> = 20
  • Sql_text dan session_id untuk sesi apa pun yang mengalami jenis kesalahan "memori" seperti 17803, 701, dll. (Kami menambahkan ini karena tidak semua kesalahan memori adalah tingkat keparahan> = 20)
  • Catatan masalah "tidak menghasilkan" (Anda terkadang melihat ini di ERRORLOG sebagai Msg 17883)
  • Kebuntuan yang terdeteksi
  • Callstack, sql_text, dan session_id untuk setiap sesi yang telah menunggu kait (atau sumber daya menarik lainnya) selama> 15 detik
  • Callstack, sql_text, dan session_id untuk sesi apa pun yang telah menunggu kunci> 30 detik
  • Callstack, sql_text, dan session_id untuk setiap sesi yang telah menunggu untuk periode waktu yang lama untuk menunggu "eksternal" atau "menunggu lebih dulu".

Dari Gunakan sesi acara system_health (MSDN) , daftar agak diperluas di SQL Server 2012 (dan tetap sama untuk SQL Server 2014):

  • The sql_text dan session_id untuk setiap sesi yang menemukan kesalahan yang memiliki tingkat keparahan> = 20.
  • Sql_text dan session_id untuk setiap sesi yang mengalami kesalahan terkait memori. Kesalahan termasuk 17803, 701, 802, 8645, 8651, 8657 dan 8902.
  • Catatan masalah penjadwal yang tidak menghasilkan apa pun. (Ini muncul di log galat SQL Server sebagai galat 17883.)
  • Kebuntuan yang terdeteksi.
  • Callstack, sql_text, dan session_id untuk setiap sesi yang telah menunggu kait (atau sumber daya menarik lainnya) selama> 15 detik.
  • Callstack, sql_text, dan session_id untuk sesi apa pun yang telah menunggu kunci> 30 detik.
  • Callstack, sql_text, dan session_id untuk setiap sesi yang telah menunggu lama untuk menunggu preemptive. Durasi bervariasi berdasarkan jenis tunggu. Pencegahan preemptive adalah di mana SQL Server menunggu panggilan API eksternal.
  • Callstack dan session_id untuk alokasi CLR dan kegagalan alokasi virtual.
  • Peristiwa ring_buffer untuk broker memori, monitor penjadwal, simpul memori OOM, keamanan, dan konektivitas.
  • Komponen sistem dihasilkan dari sp_server_diagnostics.
  • Kesehatan instan dikumpulkan oleh scheduler_monitor_system_health_ring_buffer_recorded.
  • Kegagalan alokasi CLR.
  • Kesalahan konektivitas menggunakan connection_ring_buffer_recorded.
  • Kesalahan keamanan menggunakan security_error_ring_buffer_recorded.

Di SQL Server 2016, dua peristiwa lagi ditangkap:

  • Ketika suatu proses terbunuh menggunakan KILLperintah.
  • Ketika SQL Server shutdown telah dimulai.

(Dokumentasi belum diperbarui, tetapi saya membuat blog tentang bagaimana saya menemukan ini dan perubahan lainnya .)

Untuk mendapatkan lebih banyak konfigurasi samar yang berlaku untuk versi spesifik Anda, Anda selalu dapat menjalankan kueri berikut secara langsung, tetapi Anda harus menafsirkan nama dan menguraikan predikat agar cocok dengan daftar bahasa yang lebih alami di atas:

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;

Jika Anda menggunakan Grup yang Tersedia, ada juga dua sesi baru yang Anda temukan berjalan: AlwaysOn_failoverdan AlwaysOn_health. Anda dapat melihat data yang mereka kumpulkan dengan permintaan berikut:

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;

Sesi acara ini menggunakan target penyangga dering untuk menyimpan data, jadi - seperti kumpulan buffer dan cache rencana - acara yang lebih lama akan dihapus, sehingga Anda tidak akan selalu dapat menarik acara dari rentang tanggal yang Anda inginkan.

Contoh

Dalam pertanyaan saya mengajukan pertanyaan fiktif ini:

Berapa banyak kesalahan terkait memori yang terjadi hari ini?

Berikut ini contoh (dan mungkin tidak terlalu efisien) kueri yang dapat menarik informasi ini dari system_healthsesi:

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

(Contoh ini meminjam secara longgar dari posting blog pengantar Amit Banerjee pada system_healthsesi tersebut .)

Untuk informasi lebih lanjut tentang Peristiwa Diperpanjang (termasuk banyak contoh di mana Anda dapat meminta data tertentu), lihat seri blog 31 bagian ini oleh Jonathan Kehayias:

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

Catatan eror

SQL Server secara default menyimpan file log kesalahan saat ini ditambah 6 terbaru (tetapi Anda dapat mengubahnya ). Banyak informasi disimpan di sana, termasuk informasi startup (berapa inti yang digunakan, apakah halaman kunci dalam memori diatur, mode otentikasi, dll.) Serta kesalahan dan skenario lain yang cukup parah untuk didokumentasikan (dan tidak ditangkap di tempat lain). Salah satu contoh terbaru adalah seseorang yang mencari ketika database diambil offline. Anda dapat menentukan ini dengan memindai setiap 7 log kesalahan terbaru untuk teks 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';

Saya membahas beberapa detail lain dalam jawaban baru-baru ini , dan ada juga beberapa informasi latar belakang yang baik di toadworld dan juga dalam dokumentasi resmi .

Satu kelompok "kesalahan" yang dicatat oleh log kesalahan secara default - dan dapat membuat informasi penting jatuh lebih cepat - adalah setiap pesan cadangan yang berhasil. Anda dapat mencegah ini mengisi log kesalahan dengan noise dengan mengaktifkan jejak jejak 3226 .

Aaron Bertrand
sumber