现在,我已在 SQL Server 存储引擎团队担任开发人员多年,虽然我自认为已经相当精通 C、C++ 和汇编编程程序,但从 XML 数据中通过编程方式找出提取事件负载字段所需的代码仍花了我数小时的时间。我并不是要劝阻您使用扩展事件,相反,我只是告诫您如果还不熟悉 XML 数据的使用,那么最好在查看结果前对学习曲线有所准备。
我的具体情况是这样的:我是一名 DBA,使用 SQL Server 2008 的资源管理器功能在公司的其中一台生产服务器上对各种组合进行沙箱测试。我创建了两个资源管理器资源池(开发部和市场部),用来表示使用该服务器的团队。利用资源管理器可以限制每个池的 CPU 和查询执行内存使用情况,但不能限制它们所使用的 I/O 资源数量。因此,我想根据各个团队在该服务器上的 I/O 使用情况向其开具账单,以建立一种摊销升级到新 SAN(存储区域网络)所花成本的退单机制。
我设想触发捕获 I/O 信息的非常好的时机是在任何 T-SQL 语句完成时,并且我还知道数据包 package0 中有一个名为 sql_statement_completed 的事件。那么在事件负载中都收集到了哪些数据呢?
执行下列代码将为我提供所有数据的列表(既包括读取的,也包括写入的):
WHERE [object_name] = 'sql_statement_completed';
GO
我并不认为这些是实际的读取和写入(这时数据是从磁盘读取或向磁盘写入,而不是仅在缓冲池的内存中),但它们可使我了解各个团队使用的 I/O 资源的比例。
现在,我需要找出究竟是哪个团队执行了哪个特定的 T-SQL 语句,因此需要有一个动作来通知我。执行此代码可以为我提供事件触发时我所能采取的所有动作的列表,其中包括在 sqlserver 数据包中收集 session_resource_pool_id 的动作:
FROM sys.dm_xe_objects xo, sys.dm_xe_packages xp
WHERE xp.[guid] = xo.[package_guid]
AND xo.[object_type] = 'action'
ORDER BY xp.[name];
我可以得到已为资源管理器定义的资源池的列表,并将其与扩展事件会话所收集到的 ID 相关联。现在我已准备好定义会话。请注意,在执行此代码时,将首先检查是否存在相同名称的事件会话。如果发现具有同名的事件会话,它会将其删除。以下是相关代码:
SELECT * FROM sys.server_event_sessions
WHERE name = 'MonitorIO')
DROP EVENT SESSION MonitorIO ON SERVER;
GO
CREATE EVENT SESSION MonitorIO ON SERVER
ADD EVENT sqlserver.sql_statement_completed
(ACTION (sqlserver.session_resource_pool_id))
ADD TARGET package0.ring_buffer;
GO
然后它将创建一个包含单个事件 sql_statement_completed 的新会话,同时执行 session_resource_pool_id 动作,将所有内容都记录到环缓冲区中(此时我仍在原型设计阶段)。(在生产中,我很可能会选择使用异步文件目标。)
要启动会话,需要执行下列代码:
STATE = START;
GO
现在它已启动并开始运行。
在模拟了市场部和开发部的一些活动后,我已做好对会话结果进行分析的准备。下列代码将从环缓冲区中提取数据:
FROM sys.dm_xe_session_targets xest
JOIN sys.dm_xe_sessions xes ON
xes.address = xest.event_session_address
WHERE xest.target_name = 'ring_buffer'
AND xes.name = 'MonitorIO';
GO