扩展事件的目标

适用于: SQL Server Azure SQL 数据库 Azure SQL 托管实例

本文介绍何时以及如何使用扩展事件目标。 对于每个目标,本文介绍:

  • 其收集和报告由事件发送的数据的能力
  • 其参数(浅显易懂的参数除外)

下表描述了每个目标类型在不同数据库引擎中的可用性。

目标类型 SQL Server Azure SQL Database Azure SQL 托管实例
etw_classic_sync_target
event_counter
event_file
event_stream
histogram
pair_matching
ring_buffer

先决条件

若要充分利用本文,应:

参数、操作和字段

CREATE EVENT SESSION 语句是扩展事件的中心所在。 若要编写该语句,需要以下各项:

  • 要添加到会话的事件
  • 与每个所选事件关联的字段
  • 与要添加到会话的每个目标关联的参数

从系统视图返回此类列表的 SELECT 语句可从以下文章的 C 节中复制:

可从 B2 部分(T-SQL 透视)查看实际 CREATE EVENT SESSION 语句的上下文中使用的参数、字段和操作。

etw_classic_sync_target 目标

在 SQL Server 中,扩展事件可以和 Windows 事件跟踪 (ETW) 相互操作来监视系统活动。 有关详细信息,请参阅:

此 ETW 目标同步处理其接收的数据,而大多数目标则是异步处理。

注意

Azure SQL 托管实例和 Azure SQL 数据库不支持 etw_classic_sync_target 目标。 作为替代方法,可以使用具有存储在 Azure 存储中的 Blob 的 event_file 目标。

event_counter 目标

event_counter 目标对每个指定事件发生的次数进行计数。

与大多数其他目标不同:

  • event_counter 目标没有参数。
  • event_counter 目标同步处理其接收的数据。

示例输入由 event_counter 目标捕获

package_name   event_name         count
------------   ----------         -----
sqlserver      checkpoint_begin   4

接下来是返回之前结果的 CREATE EVENT SESSION 语句。 在本示例中,WHERE 子句谓词中使用 package0.counter 字段在计数达到 4 之后停止计数。

CREATE EVENT SESSION [event_counter_1]
    ON SERVER
    ADD EVENT sqlserver.checkpoint_begin   -- Test by issuing CHECKPOINT; statements.
    (
        WHERE [package0].[counter] <= 4   -- A predicate filter.
    )
    ADD TARGET package0.event_counter
    WITH
    (
        MAX_MEMORY = 4096 KB,
        MAX_DISPATCH_LATENCY = 3 SECONDS
    );

event_file 目标

event_file 目标可将来自于缓冲的事件会话输出写入到磁盘文件或 Azure 存储中的 blob 中:

  • ADD TARGET 子句中指定 filename 参数。 文件扩展名必须为 xel
  • 系统会将你选择的文件名用作基于日期时间的长整型的前缀,后接 xel 扩展名。

注意

Azure SQL 托管实例和 Azure SQL 数据库在 Azure 存储中仅 blob 为 filename 参数的值。

有关 SQL 数据库或 SQL 托管实例特定的 event_file 代码示例,请参阅 SQL 数据库中扩展事件的事件文件目标代码

使用 event_file 目标的 CREATE EVENT SESSION

下面是一个 CREATE EVENT SESSION 示例,其中包含可添加 event_file 目标的 ADD TARGET 子句。

CREATE EVENT SESSION [locks_acq_rel_eventfile_22]
    ON SERVER
    ADD EVENT sqlserver.lock_acquired
    (
        SET
            collect_database_name=(1),
            collect_resource_description=(1)
        ACTION (sqlserver.sql_text,sqlserver.transaction_id)
        WHERE
        (
            [database_name]=N'InMemTest2'
            AND
            [object_id]=370100359
        )
    ),
    ADD EVENT sqlserver.lock_released
    (
        SET
            collect_database_name=1,
            collect_resource_description=1
        ACTION(sqlserver.sql_text,sqlserver.transaction_id)
        WHERE
        (
            [database_name]=N'InMemTest2'
            AND
            [object_id]=370100359
        )
    )
    ADD TARGET package0.event_counter,
    ADD TARGET package0.event_file
    (
        SET filename=N'C:\temp\locks_acq_rel_eventfile_22-.xel'
    )
    WITH
    (
        MAX_MEMORY=4096 KB,
        MAX_DISPATCH_LATENCY=10 SECONDS
    );

sys.fn_xe_file_target_read_file() 函数

event_file 目标以二进制格式(不可人工读取)存储其接收的数据。 可以使用 sys.fn_xe_file_target_read_file 函数来代表作为关系行集的 xel 文件的内容。

对于 SQL Server 2016 及更高版本,请使用类似于以下示例的 SELECT 语句。

SELECT f.*
--,CAST(f.event_data AS XML)  AS [Event-Data-Cast-To-XML]  -- Optional
FROM sys.fn_xe_file_target_read_file(
    'C:\temp\locks_acq_rel_eventfile_22-*.xel', NULL, NULL, NULL)  AS f;

对于 SQL Server 2014,请使用类似于以下示例的 SELECT 语句。 SQL Server 2014 后不再使用 xem 文件。

SELECT f.*
--,CAST(f.event_data AS XML)  AS [Event-Data-Cast-To-XML]  -- Optional
FROM sys.fn_xe_file_target_read_file(
    'C:\temp\locks_acq_rel_eventfile_22-*.xel', 'C:\temp\metafile.xem', NULL, NULL) AS f;

在这两个示例中,* 通配符用读取所有以指定前缀开头的 xel 文件。

在 Azure SQL 数据库中,在创建包含对包含 xel blob 的容器具有 ReadList 权限的 SAS 令牌的数据库范围凭据后,可以调用 sys.fn_xe_file_target_read_file() 函数:

/*
Create a master key to protect the secret of the credential
*/
IF NOT EXISTS (
    SELECT 1
    FROM sys.symmetric_keys
    WHERE name = '##MS_DatabaseMasterKey##'
)
CREATE MASTER KEY;

/*
(Re-)create a database scoped credential.
The name of the credential must match the URI of the blob container.
*/
IF EXISTS (
    SELECT *
    FROM sys.database_credentials
    WHERE name = 'https://exampleaccount4xe.blob.core.windows.net/extended-events-container'
)
DROP DATABASE SCOPED CREDENTIAL [https://exampleaccount4xe.blob.core.windows.net/extended-events-container];

/*
The secret is the SAS token for the container. The Read and List permissions are set.
*/
CREATE DATABASE SCOPED CREDENTIAL [https://exampleaccount4xe.blob.core.windows.net/extended-events-container]
    WITH IDENTITY = 'SHARED ACCESS SIGNATURE',
        SECRET = 'sp=rl&st=2023-10-09T22:12:54Z&se=2023-10-10T06:12:54Z&spr=https&sv=2022-11-02&sr=c&sig=REDACTED';

/*
Return event session data
*/
SELECT f.*
--,CAST(f.event_data AS XML)  AS [Event-Data-Cast-To-XML]  -- Optional
FROM sys.fn_xe_file_target_read_file('https://exampleaccount4xe.blob.core.windows.net/extended-events-container/event-session-1', DEFAULT, DEFAULT, DEFAULT) AS f;

在 Azure SQL 托管实例中,在创建包含对包含 xel blob 的容器具有 ReadList 权限的 SAS 令牌的服务器凭据后,可以调用 sys.fn_xe_file_target_read_file() 函数:

IF NOT EXISTS (
    SELECT 1
    FROM sys.symmetric_keys
    WHERE name = '##MS_DatabaseMasterKey##'
)
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'REDACTED';

/*
(Re-)create a database scoped credential.
The name of the credential must match the URI of the blob container.
*/
IF EXISTS (
    SELECT *
    FROM sys.credentials
    WHERE name = 'https://exampleaccount4xe.blob.core.windows.net/extended-events-container'
)
DROP CREDENTIAL [https://exampleaccount4xe.blob.core.windows.net/extended-events-container];

/*
The secret is the SAS token for the container. The Read and List permissions are set.
*/
CREATE CREDENTIAL [https://exampleaccount4xe.blob.core.windows.net/extended-events-container]
    WITH IDENTITY = 'SHARED ACCESS SIGNATURE',
        SECRET = 'sp=rl&st=2023-10-09T22:12:54Z&se=2023-10-10T06:12:54Z&spr=https&sv=2022-11-02&sr=c&sig=REDACTED';

/*
Return event session data
*/
SELECT f.*
--,CAST(f.event_data AS XML)  AS [Event-Data-Cast-To-XML]  -- Optional
FROM sys.fn_xe_file_target_read_file('https://exampleaccount4xe.blob.core.windows.net/extended-events-container/event-session-1', DEFAULT, DEFAULT, DEFAULT) AS f;

提示

如果在 sys.fn_xe_file_target_read_file() 的第一个参数中指定的是 blob 名称前缀而不是完整的 blob 名称,则该函数将会返回与该前缀匹配的容器中所有 blob 的数据。 这样就可以从给定事件会话的所有滚动更新文件中检索数据,而无需使用 * wild卡,Azure 存储不支持这些文件。

前面的 Azure SQL 示例省略了 xel 扩展以读取名为“event-session-1”的会话的所有滚动更新文件。

event_file 目标中存储的数据

这是 SQL Server 2016(13.x)及更高版本中返回 sys.fn_xe_file_target_read_file 的数据示例。

module_guid                            package_guid                           object_name     event_data                                                                                                                                                                                                                                                                                          file_name                                                      file_offset
-----------                            ------------                           -----------     ----------                                                                                                                                                                                                                                                                                          ---------                                                      -----------
D5149520-6282-11DE-8A39-0800200C9A66   03FDA7D0-91BA-45F8-9875-8B6DD0B8E9F2   lock_acquired   <event name="lock_acquired" package="sqlserver" timestamp="2016-08-07T20:13:35.827Z"><action name="transaction_id" package="sqlserver"><value>39194</value></action><action name="sql_text" package="sqlserver"><value><![CDATA[  select top 1 * from dbo.T_Target;  ]]></value></action></event>   C:\temp\locks_acq_rel_eventfile_22-_0_131150744126230000.xel   11776
D5149520-6282-11DE-8A39-0800200C9A66   03FDA7D0-91BA-45F8-9875-8B6DD0B8E9F2   lock_released   <event name="lock_released" package="sqlserver" timestamp="2016-08-07T20:13:35.832Z"><action name="transaction_id" package="sqlserver"><value>39194</value></action><action name="sql_text" package="sqlserver"><value><![CDATA[  select top 1 * from dbo.T_Target;  ]]></value></action></event>   C:\temp\locks_acq_rel_eventfile_22-_0_131150744126230000.xel   11776

histogram 目标

histogram 目标可实现以下功能:

  • 单独计数多个项的出现次数
  • 计数不同类型的项的出现次数:
    • 事件字段
    • 操作

histogram 目标同步处理其接收的数据。

source_type 参数是控制 histogram 目标的关键:

  • source_type=0:收集某个事件字段的数据。
  • source_type=1:收集某个操作的数据。 这是默认情况。

slots”参数默认值为 256。 如果指定另一个值,该值将四舍五入为下一个 2 的幂。 例如,slots=59 四舍五入为 64。 histogram 目标的最大直方图槽数量为 16384。

使用 histogram 命令作为目标时,有时可能会看到意外结果。 某些事件可能不会出现在预期的槽中,而其他槽则可能显示比预期的事件计数更高的计数。

如果将事件分配到槽时发生哈希冲突,则可能会发生这种情况。 虽然这种情况很少见,如果发生哈希冲突,则本应在一个槽中计数的事件会计入到另一个槽中。 出于此原因,应注意假设事件未发生,只是因为特定槽中的计数显示为零。

例如,请考虑以下情形:

  • 设置扩展事件会话,使用 histogram 作为目标并按 object_id 进行分组,以便收集存储过程执行。
  • 执行存储过程 A。然后再执行存储过程 B。

如果两个存储过程的 object_id 所返回哈希函数的值相同,直方图显示存储过程 A 被执行两次,并且存储过程 B 不会显示。

若要解决非重复值数量相对较少这一问题,请将直方图槽的数量设置得高于预期非重复值的平方。 例如,如果 histogram 目标的 source 设置为 table_name 事件字段,且数据库中有 20 个表,则 20*20 = 400。 2 比 400 大的下一个乘方是 512,也就是本示例中建议使用的槽数量。

具有操作的直方图目标

在其 ADD TARGET ... (SET ...) 子句中,以下 CREATE EVENT SESSION 语句指定目标参数赋值 source_type=1。 这表示直方图目标跟踪某项操作。

在本示例中,ADD EVENT ... (ACTION ...) 子句恰好只为目标提供了一个可选择的操作,即 sqlos.system_thread_id。 在 ADD TARGET ... (SET ...) 子句中,我们看到赋值 source=N'sqlos.system_thread_id'

注意

每个事件会话不能添加多个相同类型的目标。 包括 histogram 目标。 每个histogram目标也不能具有多个源(操作/事件字段)。 因此,需要新的事件会话来跟踪单独histogram目标中的任何其他操作或事件字段。

CREATE EVENT SESSION [histogram_lockacquired]
    ON SERVER
    ADD EVENT sqlserver.lock_acquired
        (
        ACTION
            (
            sqlos.system_thread_id
            )
        )
    ADD TARGET package0.histogram
        (
        SET
            filtering_event_name=N'sqlserver.lock_acquired',
            slots=16,
            source=N'sqlos.system_thread_id',
            source_type=1
        );

捕获到以下数据。 value 列中的值是 system_thread_id 值。 例如,236 的总锁数在 线程 6540 下取得。

value   count
-----   -----
 6540     236
 9308      91
 9668      74
10144      49
 5244      44
 2396      28

用 SELECT 发现可用操作

C.3 SELECT 语句可以查找系统上你可在 CREATE EVENT SESSION 语句中指定的操作。 在 WHERE 子句中,你将首先编辑 o.name LIKE 筛选器以匹配感兴趣的操作。

接下来介绍 C.3 SELECT 返回的示例行。 可在第二行中看到 system_thread_id 操作。

Package-Name   Action-Name                 Action-Description
------------   -----------                 ------------------
package0       collect_current_thread_id   Collect the current Windows thread ID
sqlos          system_thread_id            Collect current system thread ID
sqlserver      create_dump_all_threads     Create mini dump including all threads
sqlserver      create_dump_single_thread   Create mini dump for the current thread

具有事件字段的直方图目标

以下示例设置 source_type=0。 为 source 赋的值是事件字段。

CREATE EVENT SESSION [histogram_checkpoint_dbid]
    ON SERVER
    ADD EVENT  sqlserver.checkpoint_begin
    ADD TARGET package0.histogram
    (
    SET
        filtering_event_name = N'sqlserver.checkpoint_begin',
        source               = N'database_id',
        source_type          = 0
    );

histogram 目标捕获到以下数据。 数据显示 ID 5 的数据库经历了 7 个 checkpoint_begin 事件。

value   count
-----   -----
5       7
7       4
6       3

用 SELECT 发现所选事件上的可用字段

C.4 SELECT 语句显示可从中选择的事件字段。 首先将 o.name LIKE 筛选器编辑为所选事件的名称。

C.4 SELECT 返回以下行集。 行集显示 database_id 是可为 histogram 目标提供值的 checkpoint_begin 事件上的唯一字段。

Package-Name   Event-Name         Field-Name   Field-Description
------------   ----------         ----------   -----------------
sqlserver      checkpoint_begin   database_id  NULL
sqlserver      checkpoint_end     database_id  NULL

pair_matching 目标

pair_matching 目标可让你检测到没有对应结束事件发生的开始事件。 例如,lock_acquired 事件发生时,却没有匹配的 lock_released 事件随后及时发生,这就可能是个问题。

系统不会自动匹配开始和结束事件。 相反,你要在 CREATE EVENT SESSION 语句中向系统解释该匹配。 开始和结束事件匹配时,将弃用匹配对,以便可以专注于不匹配的开始事件。

为开始和结束事件对查找可匹配的字段

通过使用 C.4 SELECT,我们看到下列行集中有大约 16 个 lock_acquired 事件的字段。 此处显示的行集已手动拆分以显示我们的示例可匹配哪些字段。 对某些字段(如 duration),尝试匹配毫无意义。

Package-Name   Event-Name   Field-Name               Field-Description
------------   ----------   ----------               -----------------
sqlserver   lock_acquired   database_name            NULL
sqlserver   lock_acquired   mode                     NULL
sqlserver   lock_acquired   resource_0               The ID of the locked object, when lock_resource_type is OBJECT.
sqlserver   lock_acquired   resource_1               NULL
sqlserver   lock_acquired   resource_2               The ID of the lock partition, when lock_resource_type is OBJECT, and resource_1 is 0.
sqlserver   lock_acquired   transaction_id           NULL

sqlserver   lock_acquired   associated_object_id     The ID of the object that requested the lock that was acquired.
sqlserver   lock_acquired   database_id              NULL
sqlserver   lock_acquired   duration                 The time (in microseconds) between when the lock was requested and when it was canceled.
sqlserver   lock_acquired   lockspace_nest_id        NULL
sqlserver   lock_acquired   lockspace_sub_id         NULL
sqlserver   lock_acquired   lockspace_workspace_id   NULL
sqlserver   lock_acquired   object_id                The ID of the locked object, when lock_resource_type is OBJECT. For other lock resource types it will be 0
sqlserver   lock_acquired   owner_type               NULL
sqlserver   lock_acquired   resource_description     The description of the lock resource. The description depends on the type of lock. This is the same value as the resource_description column in the sys.dm_tran_locks view.
sqlserver   lock_acquired   resource_type            NULL

pair_matching 目标的示例

下面的 CREATE EVENT SESSION 语句指定两个事件和两个目标。 pair_matching 目标指定字段的两个集来将事件匹配成对。 分配给 begin_matching_columnsend_matching_columns 的以逗号分隔的字段序列必须相同。 即使空格正确,但是以逗号分隔的值中所涉及的字段之间不允许有制表符或换行符。

若要缩小结果范围,我们首先从 sys.objects 中进行选择来查找测试表的 object_id。 我们在 ADD EVENT ... (WHERE ...) 子句为那个对象 ID 添加了一个筛选器。

CREATE EVENT SESSION [pair_matching_lock_a_r_33]
    ON SERVER
    ADD EVENT sqlserver.lock_acquired
    (
        SET
            collect_database_name = 1,
            collect_resource_description = 1
        ACTION (sqlserver.transaction_id)
        WHERE
        (
            [database_name] = 'InMemTest2'
            AND
            [object_id] = 370100359
        )
    ),
    ADD EVENT sqlserver.lock_released
    (
        SET
            collect_database_name = 1,
            collect_resource_description = 1
        ACTION (sqlserver.transaction_id)
        WHERE
        (
            [database_name] = 'InMemTest2'
            AND
            [object_id] = 370100359
        )
    )
    ADD TARGET package0.event_counter,
    ADD TARGET package0.pair_matching
    (
        SET
            begin_event = N'sqlserver.lock_acquired',
            begin_matching_columns =
                N'resource_0, resource_1, resource_2, transaction_id, database_id',
            end_event = N'sqlserver.lock_released',
            end_matching_columns =
                N'resource_0, resource_1, resource_2, transaction_id, database_id',
            respond_to_memory_pressure = 1
    )
    WITH
    (
        MAX_MEMORY = 8192 KB,
        MAX_DISPATCH_LATENCY = 15 SECONDS
    );

若要测试事件会话,我们故意阻止已获取的两把锁被释放。 通过以下 T-SQL 步骤达到此目的:

  1. BEGIN TRANSACTION
  2. UPDATE MyTable...
  3. 在检查目标之前,有意不提出问题 COMMIT TRANSACTION
  4. 测试后,我们提出了 COMMIT TRANSACTION

简单的 event_counter 目标提供以下输出行。 因为 52-50=2,输出结果意味着,检查成对匹配目标中的输出时,我们会看到 2 个不成对的 lock_acquired 事件。

package_name   event_name      count
------------   ----------      -----
sqlserver      lock_acquired   52
sqlserver      lock_released   50

pair_matching 目标提供以下输出。 正如 event_counter 输出所示,我们的确看到两个 lock_acquired 行。 我们会看到这些行的这一事实,意味着两个 lock_acquired 事件不成对。

package_name   event_name      timestamp                     database_name   duration   mode   object_id   owner_type   resource_0   resource_1   resource_2   resource_description   resource_type   transaction_id
------------   ----------      ---------                     -------------   --------   ----   ---------   ----------   ----------   ----------   ----------   --------------------   -------------   --------------
sqlserver      lock_acquired   2016-08-05 12:45:47.9980000   InMemTest2      0          S      370100359   Transaction  370100359    3            0            [INDEX_OPERATION]      OBJECT          34126
sqlserver      lock_acquired   2016-08-05 12:45:47.9980000   InMemTest2      0          IX     370100359   Transaction  370100359    0            0                                   OBJECT          34126

不成对的 lock_acquired 事件的行可能包括 sqlserver.sql_text 操作提供的 T-SQL 文本。 这会捕获获取锁的查询。

ring_buffer 目标

ring_buffer 目标仅方便在内存中进行快速简单的事件收集。 停止事件会话后,将弃用存储的输出。

在此部分中,我们还会介绍如何使用 XQuery 将环形缓冲区的 XML 表示形式转换为更容易看懂的关系行集。

提示

添加 ring_buffer 目标时,将其 MAX_MEMORY 参数设置为 1024 KB 或更小的值。 使用更大的值可能会占用更多不必要的内存。

默认情况下,SQL Server 不限制 ring_buffer 目标的 MAX_MEMORY,而在 Azure SQL 数据库和 Azure SQL 托管实例中则限制为 32MB。

如以下示例所示,通过将其转化为 XML 来使用 ring_buffer 中的数据。 转换过程中会省略任何 4MB XML 文档无法容纳下的数据。 因此,即使是使用更大的 MAX_MEMORY 值捕获环形缓冲区中的更多事件(或将此参数保留为其默认值不变),也无法使用全部数据,因为考虑到 XML 标记和 Unicode 字符串的开销问题,XML 文档大小的上限为 4MB。

例如,如果 XML 文档中的 truncated 属性设置为 1,则你知道在转换为 XML 的过程中会忽略环形缓冲区的内容:

<RingBufferTarget truncated="1" processingTime="0" totalEventsProcessed="284" eventCount="284" droppedCount="0" memoryUsed="64139">

使用 ring_buffer 目标的 CREATE EVENT SESSION

以下是创建包含 ring_buffer 目标的事件会话的示例。 在此示例中,参数 MAX_MEMORY 显示两次:一次将 ring_buffer 目标内存设置为 1024 KB,一次将事件会话缓冲区内存设置为 2 MB。

CREATE EVENT SESSION [ring_buffer_lock_acquired_4]
    ON SERVER
    ADD EVENT sqlserver.lock_acquired
    (
        SET collect_resource_description=(1)
        ACTION(sqlserver.database_name)
        WHERE
        (
            [object_id]=(370100359)  -- ID of MyTable
            AND
            sqlserver.database_name='InMemTest2'
        )
    )
    ADD TARGET package0.ring_buffer
    (
        SET MAX_EVENTS_LIMIT = 98,
            MAX_MEMORY = 1024
    )
    WITH
    (
        MAX_MEMORY = 2 MB,
        MAX_DISPATCH_LATENCY = 3 SECONDS
    );

由 ring_buffer 目标为 lock_acquired 接收的 XML 输出

通过 SELECT 语句检索时,环形缓冲区的内容以 XML 文档的形式呈现。 下面显示了一个示例。 但是,为了简洁起见,除了两个 <event> 元素,所有元素都已被删除。 此外,也删除了每个 <event> 中的大量 <data> 元素。

<RingBufferTarget truncated="0" processingTime="0" totalEventsProcessed="6" eventCount="6" droppedCount="0" memoryUsed="1032">
  <event name="lock_acquired" package="sqlserver" timestamp="2016-08-05T23:59:53.987Z">
    <data name="mode">
      <type name="lock_mode" package="sqlserver"></type>
      <value>1</value>
      <text><![CDATA[SCH_S]]></text>
    </data>
    <data name="transaction_id">
      <type name="int64" package="package0"></type>
      <value>111030</value>
    </data>
    <data name="database_id">
      <type name="uint32" package="package0"></type>
      <value>5</value>
    </data>
    <data name="resource_0">
      <type name="uint32" package="package0"></type>
      <value>370100359</value>
    </data>
    <data name="resource_1">
      <type name="uint32" package="package0"></type>
      <value>0</value>
    </data>
    <data name="resource_2">
      <type name="uint32" package="package0"></type>
      <value>0</value>
    </data>
    <data name="database_name">
      <type name="unicode_string" package="package0"></type>
      <value><![CDATA[]]></value>
    </data>
    <action name="database_name" package="sqlserver">
      <type name="unicode_string" package="package0"></type>
      <value><![CDATA[InMemTest2]]></value>
    </action>
  </event>
  <event name="lock_acquired" package="sqlserver" timestamp="2016-08-05T23:59:56.012Z">
    <data name="mode">
      <type name="lock_mode" package="sqlserver"></type>
      <value>1</value>
      <text><![CDATA[SCH_S]]></text>
    </data>
    <data name="transaction_id">
      <type name="int64" package="package0"></type>
      <value>111039</value>
    </data>
    <data name="database_id">
      <type name="uint32" package="package0"></type>
      <value>5</value>
    </data>
    <data name="resource_0">
      <type name="uint32" package="package0"></type>
      <value>370100359</value>
    </data>
    <data name="resource_1">
      <type name="uint32" package="package0"></type>
      <value>0</value>
    </data>
    <data name="resource_2">
      <type name="uint32" package="package0"></type>
      <value>0</value>
    </data>
    <data name="database_name">
      <type name="unicode_string" package="package0"></type>
      <value><![CDATA[]]></value>
    </data>
    <action name="database_name" package="sqlserver">
      <type name="unicode_string" package="package0"></type>
      <value><![CDATA[InMemTest2]]></value>
    </action>
  </event>
</RingBufferTarget>

若要查看前述的 XML,可以在事件会话处于活动状态时发出以下 SELECT。 从系统视图 sys.dm_xe_session_targets 检索的 XML 数据 。

SELECT CAST(LocksAcquired.TargetXml AS XML) AS RBufXml
INTO #XmlAsTable
FROM (
    SELECT CAST(t.target_data AS XML) AS TargetXml
    FROM sys.dm_xe_session_targets AS t
    INNER JOIN sys.dm_xe_sessions AS s
        ON s.address = t.event_session_address
    WHERE t.target_name = 'ring_buffer'
        AND s.name = 'ring_buffer_lock_acquired_4'
) AS LocksAcquired;

SELECT *
FROM #XmlAsTable;

用 XQuery 将 XML 作为行集查看

若要将前述的 XML 作为关系行集查看,通过发出以下 T-SQL 从前面的 SELECT 语句继续。 已注释的行解释了 XQuery 的每次使用。

SELECT
    -- (A)
    ObjectLocks.value('(@timestamp)[1]', 'datetime') AS [OccurredDtTm],
    -- (B)
    ObjectLocks.value('(data[@name="mode"]/text)[1]', 'nvarchar(32)') AS [Mode],
    -- (C)
    ObjectLocks.value('(data[@name="transaction_id"]/value)[1]', 'bigint') AS [TxnId],
    -- (D)
    ObjectLocks.value('(action[@name="database_name" and @package="sqlserver"]/value)[1]', 'nvarchar(128)') AS [DatabaseName]
FROM #XmlAsTable
CROSS APPLY
    -- (E)
    TargetDateAsXml.nodes('/RingBufferTarget/event[@name="lock_acquired"]') AS T(ObjectLocks);

前述 SELECT 中的 XQuery 说明

(A)

  • <event> 元素上的 timestamp= attribute's value。
  • '(...)[1]'”构造可确保每次迭代只返回 1 个值,这是 XML 数据类型变量和列的 .value() XQuery 方法的必需限制。

(B)

  • 其 name= attribute 等于“mode”的 <data> 元素内的 <text> 元素的内部值。

(C)

  • 其 name= attribute 等于“transaction_id”的 <data> 元素内的 <value> 元素的内部值。

(D)

  • <event> 包含 <action>
  • <action> 的 name= attribute 等于 database_name,且 package= attribute 等于 sqlserver(而不是 package0),则获取 <value> 元素的内部值。

(E)

  • CROSS APPLY 导致其 name 属性等于 lock_acquired 的每个单个 <event> 元素都进行重复处理。
  • 这适用于由前述 FROM 子句返回的 XML。

XQuery SELECT 的输出

接下来介绍由包括 XQuery 的前述 T-SQL 生成的行集。

OccurredDtTm              Mode    DatabaseName
------------              ----    ------------
2016-08-05 23:59:53.987   SCH_S   InMemTest2
2016-08-05 23:59:56.013   SCH_S   InMemTest2

event_stream 目标

可以在用 C# 等语言编写的 .NET 程序中使用 event_stream 目标。 C# 和其他.NET 开发人员可以通过 Microsoft.SqlServer.XEvents.Linq 命名空间里的 .NET Framework 类访问事件流。 此目标不能在 T-SQL 中使用。

如果遇到错误 25726,The event data stream was disconnected because there were too many outstanding events. To avoid this error either remove events or actions from your session or add a more restrictive predicate filter to your session. 当从 event_stream 目标进行取决时,意味着事件流填满数据的速度快于客户端使用数据的速度。 这导致数据库引擎断开与事件流的连接以避免影响数据库引擎的性能。

XEvent 命名空间