Существует довольно много ценной информации, которую 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.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)
- Запись о любых "не приносящих доход" проблемах (вы иногда видели их в ОШИБКЕ как Msg 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 для любых сеансов, которые долгое время ожидали упреждающего ожидания. Продолжительность зависит от типа ожидания. Превентивное ожидание - это когда SQL Server ожидает внешних вызовов API.
- Callstack и session_id для распределения CLR и сбоев виртуального выделения.
- События ring_buffer для брокера памяти, монитора планировщика, OOM узла памяти, безопасности и подключения.
- Системный компонент является результатом sp_server_diagnostics.
- Состояние экземпляра собрано scheduler_monitor_system_health_ring_buffer_recorded.
- Ошибки распределения CLR.
- Ошибки подключения с использованием connectivity_ring_buffer_recorded.
- Ошибки безопасности с использованием 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;
(Этот пример заимствован из вступительного сообщения Амит Банерджи в блоге о 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';
В этом недавнем ответе я рассказал о некоторых других деталях , а также о хорошей исходной информации в toadworld, а также в официальной документации .
Одна группа «ошибок», которую журнал ошибок отслеживает по умолчанию - и которая может значительно ускорить выпадение важной информации, - это каждое успешное сообщение резервного копирования. Вы можете предотвратить их заполнение журнала ошибок шумом, включив флаг трассировки 3226 .