Яку інформацію про події я можу отримати за замовчуванням від SQL Server?


60

Я часто бачу запитання, де люди хочуть дізнатися, чи сталася якась річ, або коли це сталося, або хто виконав дію. У багатьох випадках SQL Server не відстежує цю інформацію самостійно. Наприклад:

  • Хто останній виконував збережену процедуру dbo.MyProcedure?
  • Хто оновив salaryстовпчик у dbo.Employeesтаблиці?
  • Хто останній запитував dbo.Ordersтаблицю у студії менеджменту?

Але є кілька інших подій, SQL - сервер робить відстежувати тимчасово за замовчуванням, і може безпосередньо відповідати на питання, такі як:

  • Коли востаннє в базі даних AdventureWorks відбувалося автоматичне зростання, і скільки часу це зайняло?
  • Хто видалив dbo.EmployeeAuditDataтаблицю і коли?
  • Скільки помилок, пов’язаних із пам’яттю, сталося сьогодні?

Як мені отримати цю інформацію та як довго вона залишається доступною?

Відповіді:


65

Існує досить багато цінної інформації, яку SQL Server відстежує для вас за замовчуванням. З часу SQL Server 2005 з'явився "слід за замовчуванням", який працює у фоновому режимі, а з часу SQL Server 2008 сеанс розширених подій автоматично запускається, називається system_health.

Ви також можете знайти певну інформацію з журналу SQL Server помилок, журнал агента SQL Server, журнали подій Windows, а також додаткові протоколювання від таких речей , як аудит SQL Server , управління сховища даних , повідомлення про події , DML Тригери , DDL тригери , SCOM / System Center , ваші власні сліди або сеанси розширених подій або сторонні моніторингові рішення (наприклад, зроблені моїм роботодавцем, SQL Sentry ). Ви також можете ввімкнути так званий "слід чорного поля", щоб допомогти у вирішенні проблем .

Але для цієї публікації я хочу зосередити увагу на речах, які загалом увімкнено найбільше: слід за замовчуванням, сеанси розширених подій та журнал помилок.

Трасування за замовчуванням

Трасування за замовчуванням зазвичай працює в більшості систем, якщо ви його не відключили за допомогою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.E 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) , подано список даних, які можна вилучити з system_healthсеансу в SQL Server 2008 та 2008 R2:

  • Sql_text і session_id для будь-яких сеансів, які зустрічаються з помилкою помилки> = 20
  • Sql_text і session_id для будь-яких сеансів, які стикаються з помилками типу "пам'яті", такими як 17803, 701, і т. Д. (Ми додали це, оскільки не всі помилки пам'яті є серйозністю> = 20)
  • Запис про будь-які "непоступливі" проблеми (ви їх іноді бачили в ERRORLOG як Msg 17883)
  • Будь-які виявлені тупики
  • Столик викликів, sql_text і session_id для будь-яких сеансів, які чекали на засувки (або інші цікаві ресурси) протягом> 15 секунд
  • Столик дзвінків, sql_text і session_id для будь-яких сеансів, які чекали на блокування протягом> 30 секунд
  • Стойка дзвінків, 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.)
  • Будь-які виявлені тупики.
  • Стойка дзвінків, sql_text і session_id для будь-яких сеансів, які чекали на засувках (або інших цікавих ресурсах) більше 15 секунд.
  • Стойка дзвінків, sql_text і session_id для будь-яких сеансів, які чекали на блокування більше 30 секунд.
  • Стойка дзвінків, sql_text і session_id для будь-яких сеансів, які довго чекали на випереджальне очікування. Тривалість залежить від типу очікування. Передумови очікування - це те, коли SQL Server чекає зовнішніх дзвінків API.
  • Столик викликів і session_id для розподілу CLR і відмов віртуального розподілу.
  • Події ring_buffer для брокера пам'яті, монітора планувальника, OOM вузла пам'яті, безпеки та підключення.
  • Системний компонент є результатом sp_server_diagnostics.
  • Екземпляр здоров’я, зібраний програмою-планувальником_monitor_system_health_ring_buffer_recorded.
  • Збої в розподілі CLR.
  • Помилки підключення з використанням записаних на зв’язок_ring_buffer_.
  • Помилки безпеки при використанні security_error_ring_buffer_recorded.

У SQL Server 2016 фіксуються ще дві події:

  • Коли процес вбивається за допомогою KILLкоманди.
  • Коли було запущено відключення SQL Server.

(Документація ще не оновлена, але я блогів про те, як я виявляю ці та інші зміни .)

Щоб отримати більш чітко налаштовану конфігурацію, застосовну для вашої конкретної версії, ви завжди можете запустити наступний запит безпосередньо, але вам доведеться інтерпретувати імена та аналізувати предикати, щоб відповідати більш природним спискам мов, наведеним вище:

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сесії .)

Для отримання додаткової інформації про розширені події (включаючи безліч прикладів, де можна отримати запит на конкретні дані), перегляньте цю серію блогів, що складається з 31 частини Джонатана Кехаяса:

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

У цій нещодавній відповіді я висвітлював деякі інші деталі , а також є хороша довідкова інформація у світі події та також в офіційній документації .

Одна група "помилок" журналу помилок відстежує за замовчуванням - і може зробити важливу інформацію набагато швидше падати з хвоста - це кожне успішне повідомлення про резервну копію. Ви можете запобігти заповненню журналу помилок шумом, включивши прапор 3226 сліду .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.