SQL Server 默认跟踪(Trace)捕获事件详解

Posted vicliu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL Server 默认跟踪(Trace)捕获事件详解相关的知识,希望对你有一定的参考价值。

SQL Server 默认跟踪 -- 捕获事件详解

哪些具体事件默认跟踪文件能够捕获到?

--returns full list of events

SELECT * FROM sys.trace_events

--returns a full list of categories

SELECT * FROM sys.trace_categories

--returns a full list of subclass values

SELECT * FROM sys.trace_subclass_values

 

Database 事件
让我们先从第一个事件开始:Database事件。它的子类事件包括数据文件和日志文件的自动增长和收缩,以及数据库镜像状态的改变。监控文件的增长和收缩是非常重要的;它可能隐射出性能问题。每次文件的增长和收缩,SQL Server将会挂起等待磁盘系统去让文件再次可用。在这里,挂起halt,是指直到进程完成前是没有事务处理的。

 

有如下数据库事件被监控:

? Data file auto grow

? Data file auto shrink

? Database mirroring status change

? Log file auto grow

? Log file auto shrink

 

如下脚本可以列出数据文件的增长和收缩:

SELECT  TE.name AS [EventName] ,
T.DatabaseName ,
t.DatabaseID ,
t.NTDomainName ,
t.ApplicationName ,
t.LoginName ,
t.SPID ,
t.Duration ,
t.StartTime ,
t.EndTime
FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), ( SELECT TOP 1
f.[value]
FROM sys.fn_trace_getinfo(NULL) f
WHERE f.property = 2
)), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
WHERE te.name = Data File Auto Grow
OR te.name = Data File Auto Shrink
ORDER BY t.StartTime ;
 

 

该脚本的输出不会告诉你为什么增长,但是会告诉你增长花了多长事件。(关于Duration列的单位,会根据SQL Server的版本,可能是milliseconds或者microseconds)

而且,我推荐扩展这个查询语句,搜索增长时间大于1秒的数据库。这只是一个引导,可以根据自己的需求去扩展。

 

这里是另一个返回日志增长和收缩的查询语句:

SELECT TE.name AS [EventName] ,
T.DatabaseName ,
t.DatabaseID ,
t.NTDomainName ,
t.ApplicationName ,
t.LoginName ,
t.SPID ,
t.Duration ,
t.StartTime ,
t.EndTime
FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), ( SELECT TOP 1
f.[value]
FROM sys.fn_trace_getinfo(NULL) f
WHERE f.property = 2
)), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
WHERE te.name = Log File Auto Grow
OR te.name = Log File Auto Shrink
ORDER BY t.StartTime ;

 

而且要记住,这个查询不会告诉你,是否你的初级DBA在收缩数据和日志文件。在默认跟踪,我们只能找到自动增长和自动收缩的事件,并且不是通过ALTER DATABASE语句触发的。

 

Errors and Warnings事件
现在,让我们来看下一个事件:Errors and Warnings事件。可以看到,也有丰富的子事件。

当写事件到SQL Server事件日志中时,Errorlog子事件触发。当哈希匹配操作或排序操作溢出到磁盘(因为磁盘子系统是最慢的,我们的查询将变得更慢),Hash warning和Sort warnings事件会发生。只有当“Auto create statistics”选项被设置为off时,Missing column statistics事件才会发生。在这里,SQL Server说明了它可能已经关闭了一个不好的执行计划。当两个表没有连接谓词,且当所有表不止一行时,Missing join predicate事件发生。可以得到慢查询或者不可预期的结果。

 

Errors and Warnings的子类包括:

? Errorlog

? Hash warning

? Missing Column Statistics

? Missing Join Predicate

? Sort Warning

 

输出错误的脚本:

SELECT TE.name AS [EventName] ,
T.DatabaseName ,
t.DatabaseID ,
t.NTDomainName ,
t.ApplicationName ,
t.LoginName ,
t.SPID ,
t.StartTime ,
t.TextData ,
t.Severity ,
t.Error
FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), ( SELECT TOP 1
f.[value]
FROM sys.fn_trace_getinfo(NULL) f
WHERE f.property = 2
)), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
WHERE te.name = ErrorLog


注意,这个脚本没有EndTime或者Duration列。

 

另一个脚本输出排序和哈希警告:

SELECT TE.name AS [EventName] ,
v.subclass_name ,
T.DatabaseName ,
t.DatabaseID ,
t.NTDomainName ,
t.ApplicationName ,
t.LoginName ,
t.SPID ,
t.StartTime
FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), ( SELECT TOP 1
f.[value]
FROM sys.fn_trace_getinfo(NULL) f
WHERE f.property = 2
)), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
JOIN sys.trace_subclass_values v ON v.trace_event_id = TE.trace_event_id
AND v.subclass_value = t.EventSubClass
WHERE te.name = Hash Warning
OR te.name = Sort Warnings

最后,脚本会输出失效的统计信息和谓词连接:

SELECT TE.name AS [EventName] ,
T.DatabaseName ,
t.DatabaseID ,
t.NTDomainName ,
t.ApplicationName ,
t.LoginName ,
t.SPID ,
t.StartTime
FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), ( SELECT TOP 1
f.[value]
FROM sys.fn_trace_getinfo(NULL) f
WHERE f.property = 2
)), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
WHERE te.name = Missing Column Statistics
OR te.name = Missing Join Predicate

 

Full text 事件
Full text事件类显示的主要事件包括:如果Full-Text终止,你可以在事件日志中找到具体的消息;FT Crawl Started子事件表明请求已经被进程获得。FT Crawl Stopped表明要么成功完成要么被错误停止。

 

Full-Text事件包括:

? FT Crawl Aborted

? FT Crawl Started

? FT Crawl Stopped

 

这个脚本返回全文事件:

SELECT TE.name AS [EventName] ,
DB_NAME(t.DatabaseID) AS DatabaseName ,
t.DatabaseID ,
t.NTDomainName ,
t.ApplicationName ,
t.LoginName ,
t.SPID ,
t.StartTime ,
t.IsSystem
FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), ( SELECT TOP 1
f.[value]
FROM sys.fn_trace_getinfo(NULL) f
WHERE f.property = 2
)), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
WHERE te.name = FT:Crawl Started
OR te.name = FT:Crawl Aborted
OR te.name = FT:Crawl Stopped


注意,DatabaseName列是null,所以我们得用DB_NAME()函数获得数据库名。

 

Objects 事件
现在真正的探测工作开始:Objects改变。在子类中,有Altered、Created和Deleted对象。这里也包含了索引重建、统计信息更新,到数据库删除。

 

Objects事件包括:

? Object Altered

? Object Created

? Object Deleted

 

下面的脚本显示了数据库中最近的操作对象:

SELECT TE.name ,
v.subclass_name ,
DB_NAME(t.DatabaseId) AS DBName ,
T.NTDomainName ,
t.NTUserName ,
t.HostName ,
t.ApplicationName ,
t.LoginName ,
t.Duration ,
t.StartTime ,
t.ObjectName ,
CASE t.ObjectType
WHEN 8259 THEN Check Constraint
WHEN 8260 THEN Default (constraint or standalone)
WHEN 8262 THEN Foreign-key Constraint
WHEN 8272 THEN Stored Procedure
WHEN 8274 THEN Rule
WHEN 8275 THEN System Table
WHEN 8276 THEN Trigger on Server
WHEN 8277 THEN (User-defined) Table
WHEN 8278 THEN View
WHEN 8280 THEN Extended Stored Procedure
WHEN 16724 THEN CLR Trigger
WHEN 16964 THEN Database
WHEN 16975 THEN Object
WHEN 17222 THEN FullText Catalog
WHEN 17232 THEN CLR Stored Procedure
WHEN 17235 THEN Schema
WHEN 17475 THEN Credential
WHEN 17491 THEN DDL Event
WHEN 17741 THEN Management Event
WHEN 17747 THEN Security Event
WHEN 17749 THEN User Event
WHEN 17985 THEN CLR Aggregate Function
WHEN 17993 THEN Inline Table-valued SQL Function
WHEN 18000 THEN Partition Function
WHEN 18002 THEN Replication Filter Procedure
WHEN 18004 THEN Table-valued SQL Function
WHEN 18259 THEN Server Role
WHEN 18263 THEN Microsoft Windows Group
WHEN 19265 THEN Asymmetric Key
WHEN 19277 THEN Master Key
WHEN 19280 THEN Primary Key
WHEN 19283 THEN ObfusKey
WHEN 19521 THEN Asymmetric Key Login
WHEN 19523 THEN Certificate Login
WHEN 19538 THEN Role
WHEN 19539 THEN SQL Login
WHEN 19543 THEN Windows Login
WHEN 20034 THEN Remote Service Binding
WHEN 20036 THEN Event Notification on Database
WHEN 20037 THEN Event Notification
WHEN 20038 THEN Scalar SQL Function
WHEN 20047 THEN Event Notification on Object
WHEN 20051 THEN Synonym
WHEN 20549 THEN End Point
WHEN 20801 THEN Adhoc Queries which may be cached
WHEN 20816 THEN Prepared Queries which may be cached
WHEN 20819 THEN Service Broker Service Queue
WHEN 20821 THEN Unique Constraint
WHEN 21057 THEN Application Role
WHEN 21059 THEN Certificate
WHEN 21075 THEN Server
WHEN 21076 THEN Transact-SQL Trigger
WHEN 21313 THEN Assembly
WHEN 21318 THEN CLR Scalar Function
WHEN 21321 THEN Inline scalar SQL Function
WHEN 21328 THEN Partition Scheme
WHEN 21333 THEN User
WHEN 21571 THEN Service Broker Service Contract
WHEN 21572 THEN Trigger on Database
WHEN 21574 THEN CLR Table-valued Function
WHEN 21577
THEN Internal Table (For example, XML Node Table, Queue Table.)
WHEN 21581 THEN Service Broker Message Type
WHEN 21586 THEN Service Broker Route
WHEN 21587 THEN Statistics
WHEN 21825 THEN User
WHEN 21827 THEN User
WHEN 21831 THEN User
WHEN 21843 THEN User
WHEN 21847 THEN User
WHEN 22099 THEN Service Broker Service
WHEN 22601 THEN Index
WHEN 22604 THEN Certificate Login
WHEN 22611 THEN XMLSchema
WHEN 22868 THEN Type
ELSE Hmmm???
END AS ObjectType
FROM [fn_trace_gettable](CONVERT(VARCHAR(150), ( SELECT TOP 1
value
FROM [fn_trace_getinfo](NULL)
WHERE [property] = 2
)), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
JOIN sys.trace_subclass_values v ON v.trace_event_id = TE.trace_event_id
AND v.subclass_value = t.EventSubClass
WHERE TE.name IN ( Object:Created, Object:Deleted, Object:Altered )
-- filter statistics created by SQL server
AND t.ObjectType NOT IN ( 21587 )
-- filter tempdb objects
AND DatabaseID <> 2
-- get only events in the past 24 hours
AND StartTime > DATEADD(HH, -24, GETDATE())
ORDERBY t.StartTime DESC ;

 

记住,SQL Server默认有5个跟踪文件,每个20MB,没有知道的方法修改。如果你的系统很繁忙,跟踪文件会快速循环(甚至几小时内),以至你无法捕获到改变。

 

Security Audit事件
另一部分默认跟踪是Security Audit。你可以下列事件列表可以看到,它是一个丰富的默认跟踪。通常,这些时间组告诉我们的是在我们系统中发生的重要安全事件。

 

Security Audit事件包括:

? Audit Add DB user event

? Audit Add login to server role event

? Audit Add Member to DB role event

? Audit Add Role event

? Audit Add login event

? Audit Backup/Restore event

? Audit Change Database owner

? Audit DBCC event

? Audit Database Scope GDR event (Grant, Deny, Revoke)

? Audit Login Change Property event

? Audit Login Failed

? Audit Login GDR event

? Audit Schema Object GDR event

? Audit Schema Object Take Ownership

? Audit Server Starts and Stops

 

让我们一步步操作:

? 创建一个SQL Server login

? 分配读权限到数据库的用户

 

通过运行下面的脚本,我们能跟踪用户在实例上创建的对象。

SELECT TE.name AS [EventName] ,
v.subclass_name ,
T.DatabaseName ,
t.DatabaseID ,
t.NTDomainName ,
t.ApplicationName ,
t.LoginName ,
t.SPID ,
t.StartTime ,
t.RoleName ,
t.TargetUserName ,
t.TargetLoginName ,
t.SessionLoginName
FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), ( SELECT TOP 1
f.[value]
FROM sys.fn_trace_getinfo(NULL) f
WHERE f.property = 2
)), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
JOIN sys.trace_subclass_values v ON v.trace_event_id = TE.trace_event_id
AND v.subclass_value = t.EventSubClass
WHERE te.name IN ( Audit Addlogin Event, Audit Add DB User Event,
Audit Add Member to DB Role Event )
AND v.subclass_name IN ( add, Grant database access )

 

下面是我们创建登录,并给用户赋予读取权限后的结果:

 

可以看到,第一行显示在master数据库中登录的创建,以及创建者(SessionLoginName列)和创建用户(TargetLoginName列)。

下两行:创建数据库用户并授予它访问权限,并最后添加用户到DB角色。

记住,如果你添加用户到多个角色,且如果你赋予登录访问给多个数据库,然而你会看到对每一个事件会记录很多行在你的默认跟踪。

现在,让我们审核被删除的用户和登录,运行如下查询语句:

SELECT TE.name AS [EventName] ,
v.subclass_name ,
T.DatabaseName ,
t.DatabaseID ,
t.NTDomainName ,
t.ApplicationName ,
t.LoginName ,
t.SPID ,
t.StartTime ,
t.RoleName ,
t.TargetUserName ,
t.TargetLoginName ,
t.SessionLoginName
FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), ( SELECT TOP 1
f.[value]
FROM sys.fn_trace_getinfo(NULL) f
WHERE f.property = 2
)), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
JOIN sys.trace_subclass_values v ON v.trace_event_id = TE.trace_event_id
AND v.subclass_value = t.EventSubClass
WHERE te.name IN ( Audit Addlogin Event, Audit Add DB User Event,
Audit Add Member to DB Role Event )
AND v.subclass_name IN ( Drop, Revoke database access )


可以看到,对于创建和删除登录,事件名是相同的:Audit Addlogin Event;然而子类列值定义的不同:在创建登录子类是“Add”,而在删除子类是“Drop”。

事实上,如果我们删除之前创建的数据库用户和登录,这个查询会返回两行—对于每一个事件返回一行,包含被删除的用户和登录的名字,以及删除者的登录名。

 

下面的查询显示在默认跟踪文件中所有的失败的登录:

SELECT TE.name AS [EventName] ,
v.subclass_name ,
T.DatabaseName ,
t.DatabaseID ,
t.NTDomainName ,
t.ApplicationName ,
t.LoginName ,
t.SPID ,
t.StartTime ,
t.SessionLoginName
FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), ( SELECT TOP 1
f.[value]
FROM sys.fn_trace_getinfo(NULL) f
WHERE f.property = 2                   )), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
JOIN sys.trace_subclass_values v ON v.trace_event_id = TE.trace_event_id
AND v.subclass_value = t.EventSubClass
WHERE   te.name IN ( Audit Login Failed )


有大量的事件在Security Audit类,我们这里重点关注“Audit Server Starts and Stops”。

 

下面的查询将会列出服务器启动事件:

SELECT TE.name AS [EventName] ,
v.subclass_name ,
T.DatabaseName ,
t.DatabaseID ,
t.NTDomainName ,
t.ApplicationName ,
t.LoginName ,
t.SPID ,
t.StartTime ,
t.SessionLoginName
FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), ( SELECT TOP 1
f.[value]
FROM sys.fn_trace_getinfo(NULL) f
WHERE f.property = 2
)), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
JOIN sys.trace_subclass_values v ON v.trace_event_id = TE.trace_event_id
AND v.subclass_value = t.EventSubClass
WHERE   te.name IN ( Audit Server Starts and Stops )


请注意:上面的查询只返回Server Start事件,而不会返回Server Stop事件。解释是这样的:像之前所提到的,SQL Server的默认跟踪总共有5个跟踪文件组成,每个文件最大20MB。这五个文件在一些条件下会循环:当实例启动,或当文件大小超过20MB。现在,让我们想一下:我们所列出的查询返回的结果仅来自于当前的跟踪文件,最新的那一个。而因为默认跟踪文件在服务器实例启动时被循环利用,意思是包含Server Stop的事件将保留在前一个默认跟踪文件中。简而言之,在SQL服务重启后,我们当前的默认跟踪文件将有Server Start事件作为第一行。如果你真的希望知道你的SQL Server实例什么时候停止的,你需要至少包含上一个文件的内容,但事实上我们能包含其他4个默认跟踪文件的内容到我们的结果集。我们可以通过调用sys.fn_trace_gettable的方法,他能追加所有的默认跟踪文件。这个函数接受2个参数—文件的位置和名称、以及文件的数量;如果我们传入最旧的默认跟踪文件的路径和名称到第1个参数,而sys.fn_trace_gettable会追加最新的,一旦我们设置了适当的值给第2个参数(文件数量)。如果传入最新的文件给这个函数,那么旧的文件不会被追加。因为文件名包含了文件创建时候的索引,因此很容易计算最旧文件的名称。

 

找到默认跟踪文件的真实路径,你需要执行一下语句:

SELECT REVERSE(SUBSTRING(REVERSE(path), CHARINDEX(, REVERSE(path)), 256)) AS DefaultTraceLocation
FROM sys.traces
WHERE is_default = 1

 

Server事件
最后一个事件类:Server类。它只包含了一个事件—Server Memory Change。

 

下面的查询显示了什么时候内存使用改变:

SELECT TE.name AS [EventName] ,
v.subclass_name ,
t.IsSystem
FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), ( SELECT TOP 1
f.[value]
FROM sys.fn_trace_getinfo(NULL) f
WHERE f.property = 2
)), DEFAULT) T
JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
JOIN sys.trace_subclass_values v ON v.trace_event_id = TE.trace_event_id
AND v.subclass_value = t.EventSubClass
WHERE te.name IN ( Server Memory Change )


该事件子类表明了是否内存增加或减少。

 

总结
默认跟踪是一个检查SQL Server实例的健康和安全的有效方法。有些陷阱需要记住—主要是文件循环和大小限制,但是修改这一块不是不可能。重要的是,上面的查询语句是从当前最新的默认跟踪文件中获取的结果。依赖于SQL Server实例的繁忙程度,有可能文件循环太快,而DBA无法捕获所有重要的事件;因此,自动化是需要的。

原文链接

以上是关于SQL Server 默认跟踪(Trace)捕获事件详解的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server中关于跟踪(Trace)那点事

SQL Server中关于跟踪(Trace)那点事

运行SQL Server Profiler的时候,提示“您必须是 sysadmin 固定服务器角色的成员或具有 ALTER TRACE 权限,才能对 SQL Server 运行跟踪。”

您必须是 sysadmin 固定服务器角色的成员或具有 ALTER TRACE 权限,才能对 SQL Server 运行跟踪

简单使用SQL Server中的Trace Flags

简单使用SQL Server中的Trace Flags