我经常看到人们想知道某件事是否发生、何时发生或谁执行了该操作的问题。在很多情况下,SQL Server 本身并不跟踪这些信息。例如:
- 谁最后执行了存储过程
dbo.MyProcedure
? - 谁更新了表
salary
中的列dbo.Employees
? - 谁最后
dbo.Orders
从 Management Studio 查询了该表?
但是 SQL Server默认会临时跟踪其他几个事件,并且可以本机回答有关的问题,例如:
- AdventureWorks 数据库中最后一次发生自动增长是什么时候,用了多长时间?
- 谁删除了
dbo.EmployeeAuditData
表格,何时删除? - 今天发生了多少与内存相关的错误?
我如何获得这些信息,它可以保留多长时间?
默认情况下,SQL Server 会为您跟踪很多有价值的信息。自 SQL Server 2005 以来,有一个在后台运行的“默认跟踪”,自 SQL Server 2008 以来,有一个自动运行的扩展事件会话,称为
system_health
.您还可以从 SQL Server 错误日志、SQL Server 代理日志、Windows 事件日志以及来自SQL Server 审计、管理数据仓库、事件通知、DML 触发器、DDL 触发器、SCOM / System Center等其他日志记录中找到某些信息,您自己的服务器端跟踪或扩展事件会话,或第三方监控解决方案(如SentryOne制作的那些)。您还可以选择启用所谓的“黑盒跟踪”来帮助进行故障排除。
但是对于这篇文章,我将把范围集中在通常在任何地方都启用的东西上:默认跟踪、扩展事件会话和错误日志。
默认跟踪
默认跟踪通常在大多数系统上运行,除非您使用禁用它
sp_configure
- 我绝对是这样做的忠实粉丝。只要启用它,它就可以成为有价值信息的丰富来源,尽管在现代版本的 SQL Server 中,其中大部分是噪音和/或已经在其他地方捕获。下面列出了捕获的跟踪事件:您可以通过加入来了解更多详细信息,
sys.trace_columns
以查看哪些事件与哪些数据一起出现,但我现在将跳过它,因为当您实际查询特定事件的跟踪数据时,您可以看到您拥有的内容。这些是我的系统上可用的事件(您应该在您的系统上运行查询以确保它们匹配,尽管这仍然是 SQL Server 2019 CTP 2.4 的同一组事件):请注意,默认跟踪使用翻转文件,因此您可用的数据只能追溯到到目前为止 - 可用数据的日期范围取决于捕获的上述事件的数量和频率。如果您想确保保留更长的历史记录,您可以设置一个定期归档与跟踪关联的当前非活动文件的作业。
例子
在这个问题中,我问了几个我发现的问题。以下是用于从默认跟踪中提取特定信息的示例查询。
此查询将提取 AdventureWorks 数据库中的所有 AutoGrow 事件,包括日志和数据文件,它们仍位于默认跟踪日志文件中:
这将返回
DROP
名为 的对象的任何事件EmployeeAuditData
。如果你想确保它只检测DROP
表的事件,你可以添加一个过滤器:(ObjectType = 8277
完整列表记录在这里)。如果要将搜索空间限制为特定数据库,可以添加过滤器:DatabaseName = N'db_name'
.这里有一个复杂的情况,这是非常极端的情况,但无论如何都要谨慎提及。如果您使用多个模式并且可能在多个模式中具有相同的对象名称,您将无法分辨这是哪一个(除非它的对应物仍然存在)。有一种外部情况,即 UserA 可能已删除 SchemaB.Tablename 而 UserB 可能已删除 SchemaA.Tablename。默认跟踪不跟踪对象的架构(也不捕获
TextData
此事件),并且ObjectID
包含在跟踪中对直接匹配没有用(因为对象已被删除并且不再存在)。在这种情况下,在输出中包含该列可能有助于交叉引用仍然存在的同名表的任何副本,但是如果系统处于如此混乱的状态(或者如果所有此类副本都已被删除),则仍然可能不是猜测表的哪个副本被谁删除的可靠方法。扩展活动
system_health
以下是您可以从SQL Server 2008 和 2008 R2 中的会话中剔除的数据列表(该列表在现代版本中更完整):从Use the system_health event session (MSDN) 开始,该列表在 SQL Server 2012 中有所扩展(对于 SQL Server 2014 保持不变):
在 SQL Server 2016 中,还捕获了两个事件:
KILL
命令杀死进程时。(文档还没有更新,但我在博客上写了我是如何发现这些和其他变化的。)
要获得适用于您的特定版本的更神秘的配置,您始终可以直接运行以下查询,但您必须解释名称并解析谓词以匹配上面更自然的语言列表:
如果您使用的是可用性组,您还会发现两个新会话正在运行:
AlwaysOn_failover
和AlwaysOn_health
. 您可以通过以下查询查看他们收集的数据:这些事件会话使用环形缓冲区目标来存储数据,因此 - 就像缓冲池和计划缓存一样 - 较旧的事件将被逐步淘汰,因此您不一定能够从您想要的日期范围中提取事件。
例子
在这个问题中,我提出了这个虚构的问题:
system_health
这是一个可以从会话中提取此信息的示例(可能不是很有效)查询:(这个例子大致借鉴了Amit Banerjee 关于会话的介绍性博客文章
system_health
。)有关扩展事件的更多信息(包括您可以查询特定数据的许多示例),请参阅 Jonathan Kehayias 的这个由 31 部分组成的博客系列:
https://www.sqlskills.com/blogs/jonathan/an-xevent-a-day-31-days-of-extended-events/
错误日志
默认情况下,SQL Server 保留当前加上 6 个最近的错误日志文件(但您可以更改此文件)。那里存储了大量信息,包括启动信息(正在使用多少个内核,是否设置了内存中的锁定页面,身份验证模式等)以及错误和其他严重到足以记录的场景(并且没有在其他地方捕获)。最近的一个例子是有人在数据库离线时进行查找。您可以通过扫描最近的 7 个错误日志中的每一个来确定这一点
Setting database option OFFLINE
:我在这个最近的答案中介绍了一些其他细节,并且在 toadworld和官方文档中也有一些很好的背景信息。
错误日志默认跟踪的一组“错误”——并且可以使重要信息更快地从尾部消失——是每条成功的备份消息。您可以通过启用跟踪标志 3226来防止这些错误日志充满噪音。