本文属于 SQL Server 扩展事件(Extented Events)从入门到进阶 系列
在第一二节中,我们创建了一些简单的、类似典型SQL Trace的扩展事件会话。在此过程中,介绍了很多扩展事件基础组件,包括事件、谓词、操作和目标。本节,将对扩展事件引擎、架构和基本组件做更加深入的了解。通过这些讲解,可以大概了解到为什么扩展事件相对于SQL Trace来说更加低开销。另外,还会延时如何设计事件会话从而最小化事件收集过程中的不必要开销,即使这些事件会话会很复杂。
SELECT [p].[name] AS [Module] ,
[
p
].[
description
]
AS
[
Description
]
,
[
m
].[
name
]
AS
[
ModulePath
]
FROM
[
sys
].[
dm_xe_packages
]
[
p
]
JOIN
[
sys
].[
dm_os_loaded_modules
]
[
m
]
ON
[
p
].[
module_address
]
=
[
m
].[
base_address
];
GO
下面是本机的结果:
如果是在SQL 2016上运行,会有13行。而SQL 2008只有4行。本机是SQL 2014。下面的语句用于显示每个包加载了哪些事件:
SELECT [xo].[name] AS [EventName] ,
[xo].[description] AS [EventDescription] ,
[xp].[name] AS [Package]
FROM [sys].[dm_xe_objects] [xo]
JOIN [sys].[dm_xe_packages] [xp]
ON [xo].[package_guid] = [xp].[guid]
WHERE [xo].[object_type] = N'event'
ORDER BY [xo].[name];
GO
SELECT [object_name] AS [EventName] ,
[
name
]
AS
[
ElementName
]
,
[
column_id
]
AS
[
ColumnID
]
,
[
type_name
]
AS
[
ElementType
]
,
[
column_type
]
AS
[
ColumnType
]
,
[
capabilities_desc
]
AS
[
Capability
]
,
[
description
]
AS
[
ElementDescription
]
FROM
[
sys
].[
dm_xe_object_columns
]
WHERE
[
object_name
]
=
N
'sql_statement_completed'
AND
[
column_type
]
<>
'readonly'
;
GO
除了脚本形式,还可以用GUI方式查看,比如第二篇中提到的【事件】页,默认负载是不可定制化的,除了下图的红框那些:
事件列(也叫数据列)包含了列类型。我们可以把它们作为默认负载的一部分来收集,当然也可以不收集。
虽然扩展事件通常来说开销都比Trace小,但是也还是有一些事件会明显影响性能。比如showplan就是特别需要注意的,比如下图中红框部分明确提醒了:
即使加上了谓词筛选,showplan依旧具有很高开销,因为showplan_xml字段是属于默认负载。因此,在谓词生效之前,必须收集执行计划的XML数据,这个操作是一个高开销操作。
操作:
如果我们需要收集事件数据中的其他不在默认负载中的列,或者希望事件触发时同时触发另外一个操作,那么就需要显式指定一个合适的操作到事件会话中。
一旦事件触发,XE引起会收集事件的默认负载(包括里面已经启用的可选列)。并对事件会话进行谓词评估。只有事件触发并符合谓词定义的数据才会被收集,并且只有此时被 执行的操作才会被收集,这种设计还是为了最小化负载。下面脚本用于返回可用的操作:
CREATE EVENT SESSION [MyEventSession] ON SERVER
ADD
EVENT sqlserver
.
sp_statement_completed
(
SET
collect_object_name
=
(
1
)
,
collect_statement
=
(
1
)
ACTION
(
sqlserver
.
client_app_name
,
sqlserver
.
database_name
)
WHERE
(
[
logical_reads
]
>=
(
10000
)
)
);
GO
我们可以使用布尔表达式来创建谓词的逻辑块(logical blocks),这些逻辑块非常关键的,因为一旦谓词块中的逻辑评估为false,那么评估会停止,同时事件不触发。下面语句对上面的事件会话定义添加了一个AND逻辑,为了触发事件,逻辑读必须大于等于10000并且持续事件必须小于1秒(1000000 微妙)。
SELECT
[object_name] AS [Event],
[name] AS [Column],
[description] AS [Description]
FROM [sys].[dm_xe_object_columns]
WHERE [name] = 'duration'
ORDER BY [object_name];
CREATE EVENT SESSION [MyEventSession] ON SERVER
ADD EVENT sqlserver.sp_statement_completed ( SET collect_object_name = ( 1 ) ,
collect_statement = ( 1 )
ACTION ( sqlserver.client_app_name, sqlserver.database_name )
WHERE ( [sqlserver].[database_id] = ( 7 )
AND [logical_reads] >= ( 10000 )
AND [duration] >= ( 1000 )
) );
GO
SELECT [xmv].[name] ,
[xmv].[map_key] ,
[xmv].[map_value]
FROM sys.dm_xe_map_values [xmv]
JOIN sys.dm_xe_packages [xp]
ON [xmv].[object_package_guid] = [xp].[guid]
WHERE [xmv].[name] = N'wait_types';
GO
CREATE EVENT SESSION [Capture WRITELOG Waits] ON SERVER
ADD EVENT sqlos.wait_info (
WHERE ( ( [wait_type] = ( 181) )
AND ( [duration] >= ( 1000 ) )
) )
ADD TARGET package0.event_file ( SET filename = N'C:\temp\WaitInfo' );
GO
CREATE EVENT SESSION [Capture WRITELOG Waits] ON SERVER
ADD EVENT sqlos.wait_info (
WHERE ( ( [wait_type] = ( 181 ) )
AND ( [duration] >= ( 1000 ) )
) )
ADD TARGET package0.event_file ( SET filename = N'C:\temp\WaitInfo' );
GO
CREATE EVENT SESSION [TrackRecompiles] ON SERVER
ADD EVENT sqlserver.sql_statement_recompile ( SET collect_object_name = ( 1 ) ,
collect_statement = ( 1 )
WHERE ( [sqlserver].[is_system] = ( 0 ) ) )
ADD TARGET package0.histogram ( SET filtering_event_name = N'sqlserver.sql_statement_recompile' ,
slots = ( 11 ) ,
source = N'recompile_cause' ,
source_type = ( 0 ) )
WITH ( MAX_MEMORY = 4096 KB ,
EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS ,
MAX_DISPATCH_LATENCY = 30 SECONDS ,
MAX_EVENT_SIZE = 0 KB ,
MEMORY_PARTITION_MODE = NONE ,
TRACK_CAUSALITY = OFF ,
STARTUP_STATE = OFF );
GO
CREATE EVENT SESSION [Find_Unmatched_Statements] ON SERVER
ADD EVENT sqlserver.sql_statement_starting (
ACTION ( sqlserver.session_id, sqlserver.tsql_stack ) ),
ADD EVENT sqlserver.sql_statement_completed (
ACTION ( sqlserver.session_id, sqlserver.tsql_stack ) )
ADD TARGET package0.pair_matching ( SET begin_event = N'sqlserver.sql_statement_starting' ,
begin_matching_actions = N'sqlserver.session_id, sqlserver.tsql_stack' ,
end_event = N'sqlserver.sql_statement_completed' ,
end_matching_actions = N'sqlserver.session_id, sqlserver.tsql_stack' ,
respond_to_memory_pressure = ( 0 )
)
WITH ( MAX_MEMORY = 4096 KB ,
EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS ,
MAX_DISPATCH_LATENCY = 30 SECONDS ,
MAX_EVENT_SIZE = 0 KB ,
MEMORY_PARTITION_MODE = NONE ,
TRACK_CAUSALITY = OFF ,
STARTUP_STATE = OFF );
GO