本文属于 SQL Server 扩展事件(Extented Events)从入门到进阶 系列
第一篇文章中提到了如何在Profiler中创建跟踪(trace),并以服务器端(server-side)跟踪方式运行以便在服务器上创建实际跟踪文件。接着把跟踪定义转换到扩展事件的CREATE EVENT SESSION脚本中。
上一篇文章可以成为你从SQL Trace通往扩展事件(Extented Events/xEvents,为后续编写方便,本人尽可能使用xEvents替代扩展事件)的桥梁。同时,上文也从中展示了如何把现有的跟踪库转成xEvents。
但是你应该如何从零开始创建一个新的xEvents?当然T-SQL完全可以实现。虽然从SQL 2008开始引入xEvents,但是真正集成到SSMS(即GUI)中还是从SQL 2012开始,所以如果你要在2008中使用,只能使用T-SQL。从SQL 2012开始,就可以使用GUI来实现。作为扩展事件入门的切入点,从SSMS开始是不错的选择,也正是本文的目的所在。
本节会通过GUI界面,创建一个新的事件会话(event session),并对其定义、启用、筛选和建立会话目标从而实现数据收集。
从GUI开始:
在SQL Server 2008/2008 R2中,没有xEvents的GUI界面可供使用,如果你正在使用这些版本又希望使用扩展事件,那么要么使用T-SQL操作,要么就在SQL 2012的SSMS中进行(无论是SSMS 2012直连2008实例还是在2012中建好然后把脚本在2008实例中执行)。
本系列中,推荐使用SQL 2012及以上版本。当你在SSMS中使用扩展事件时,可以通过下图所示展开:
正如在上一文中提到过,xEvents的其中一个优势是事件会话定义存储在服务器的元数据中,即使重启也会默认启动,而trace却需要手动或者经过某些配置来实现,比如在重启后自动运行某些自定义存储过程来启动跟踪。另外我们也可以有多个事件会话,但是不启用。虽然trace也能实现,但是因为trace的输出文件需要硬编码到定义中,而且如果我们停止跟踪重新启动的话,要确保输出文件名不存在,或者配置跟踪定义允许其滚动使用同一个文件。而xEvents解决了这个问题,在本文后续部分会介绍。
右键上图的“XE_ReadsFilter_Trace”会话,然后按下图选择,把会话定义显示在新建窗口中,这段代码有第一篇中的sp_SQLskills_ConvertTraceToExtendedEvents存储过程生成,但是对比两部分的代码可以看到一些细节差异。首先,SQL Server中存储的代码不在包含注释。
其次,SQL Server产生的代码最下方WITH子句中包含了一系列服务器级别选项,将在下一节介绍。这些选项都是默认项,而第一篇中的脚本不包含这部分。
生成脚本:
CREATE EVENT SESSION [XE_ReadsFilter_Trace] ON SERVER ADD EVENT sqlserver.rpc_completed ( ACTION ( sqlserver.client_app_name , sqlserver.database_id , sqlserver.server_instance_name , sqlserver.session_id ) WHERE ( logical_reads >= 10000 ) ), ADD EVENT sqlserver.sql_statement_completed ( ACTION ( sqlserver.client_app_name , sqlserver.database_id , sqlserver.server_instance_name , sqlserver.session_id ) WHERE ( logical_reads >= 10000 ) ) ADD TARGET package0.event_file ( SET filename = 'D:\temp\XE_ReadsFilter_Trace.xel' , max_file_size = ( 5 ) , max_rollover_files = ( 1 ) ) 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
接下来,我们使用GUI来创建一个相同的事件会话,但是为了避免重名冲突,会使用另外一名字,然后使用SQL Server生成的脚本对比两者的区别。
在GUI中创建新的事件会话:
常规页:
事件页:
添加事件:
通过界面创建会话时,必须添加最少一个事件。比如,我们想添加两个事件:sqlserver.sql_statement_completed和sqlserver.rpc_completed。我挺喜欢这个界面的搜索功能。如果单纯使用滚动条,可能会耗费数分钟、数小时数天等等。因为里面有包含在Profiler中的180个事件,从中找一个你需要的是非常痛苦的事情。通过搜索,可以很快定位。
比如在“事件库”中输入“completed”,然后自动会触发搜索,从数百个事件中筛选出少于15个:
注意【类别/通道】两列,这是基于Windows事件跟踪(Event Tracing for Windows,ETW)分类系统的。这部分在后续章节介绍。
但是这里没有显示所有“_completed”事件,因为默认情况下,GUI不现实debug通道事件。你可以展开【通道】列的箭头,会发现debug是没选中的,如图:
如果勾选这个debug项,你可以发现多了几个事件。debug 事件的目的是给微软内部使用。也可以给数据库专家在进行深入Troubleshooting时使用,或者用来深入研究SQL Server内部特性时使用。但是基于其目的,微软不支持非内部人员这样使用,也不确保提供这种功能,同时可能会在后续版本中移除。
双击【所选事件】中的任意一个,界面就会平移到配置项,或者单击事件名然后点下图红圈中的按钮。这个配置页用于添加对应事件的操作和限定谓词。
这部分是作者唯一不喜欢的GUI功能,因为配置不能在同一个窗体内完成,需要平移。
配置事件:
在这两个事件中切换时可以看到不同的事件的默认负载略有不同。并且绝大部分不能移除。通过复选框可以控制是否收集。比如rpc_completed事件的statement部分是可以不收集的,但默认会收集,而output_parameters列是可选但默认不收集。这里我们不改动任何默认设置。
添加操作:
上面这四个操作很轻量级,只是对事件添加一些明细信息。但是扩展事件也提供了一些有副作用的操作,称为“副作用操作”(side-effecting actions)。比如,debug_break操作会在事件触发时引发一个debug断点,另外“create_dump_all_threads”、“create_dump_single_thread”会触发SQL Server记录下所有或者正在运行的线程的内存使用情况。由于引擎在同一个线程中执行这些操作,所以这些操作会降低性能,需要谨慎使用。这部分在下文介绍。
设置筛选条件(谓词):
最后,我们通过【筛选器(谓词)】页配置筛选条件。除了少数特殊情况之外,都应该对每个事件配置筛选条件,以便实现“短路(short-circuit)”事件评估,并且避免扩展事件引擎收集不必要的数据从而增大整体开销。筛选配置和短路逻辑极其重要,下节会做详细介绍。
在本例中,高亮所有事件,然后在【字段】列的下拉框中选择【logical_reads】,【运算符】列选择【>=】,【值】列输入100000,通过这些配置,事件会话只会收集超过10000逻辑读的SQL语句或者存储过程:
这里是对所有事件进行指定筛选条件,使得全局通用的筛选都能应用于多个事件中。但是根据事件的不同,并不是所有的字段都是可用的。比如如果添加了error_reported事件,并且选择了三个事件,那么就看不到“logical_reads”这个操作符,甚至你会发现完全不可选:
在这个例子中,对两个事件添加了相同的谓词,但是我们也可以对每个事件单独配置,这一点在SQL Trace中是不可能的。
在配置完之后,点击【确定】来创建事件会话。因为已经添加了最少一个事件,已经满足了最低要求。在这里并不强制定义事件会话的目标。这种免选择对一些事件来说是合理的。比如配置带有create_dump_single_thread这种副作用操作的error_reported事件,就没有必要非要指定目标,我们想要的数据(一个文件)将在特定错误发生时会创建。
由于本例中我们只是配置针对会话的目标,所以对数据存储非必要。但是下面还是介绍一下。
数据存储页:定义目标
高级会话选项:
事件会话DDL:
/*Create the session, named as specified on the General page*/ CREATE EVENT SESSION [HighReadQueries] ON SERVER /*Add and configure events, actions and predicates, as specified on the Events page*/ ADD EVENT sqlserver.rpc_completed ( ACTION ( sqlserver.client_app_name, sqlserver.database_id, sqlserver.server_instance_name, sqlserver.session_id ) WHERE ( [logical_reads] >= ( 100000 ) ) ), ADD EVENT sqlserver.sql_statement_completed ( ACTION ( sqlserver.client_app_name, sqlserver.database_id, sqlserver.server_instance_name, sqlserver.session_id ) WHERE ( [logical_reads] >= ( 100000) ) ) /*Add and configure a target, as specified on the Data Storage page*/ ADD TARGET package0.event_file ( SET filename = N'D:\temp\HighReadQueries' ) /* Set Session-level options, specified on the General and Advanced pages*/ 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 = ON ); GO