SQL Server数据库接收到查询请求,从生成计划到执行计划的过程,等待次数和等待时间在一定程度上揭示了系统性能的压力,如果资源严重不足,就会成为性能的瓶颈。因此,对等待的监控非常有助于对系统性能进行诊断,对查询语句进行性能调优。偶尔一次的异常等待,不足以表明系统存在瓶颈,但是,SQL Server实例经常出现特定的等待类型,并且等待时间趋于增加,这就说明,系统存在压力,或内存,或IO等,根据WaitType对系统进行监控和诊断,还能对查询进行性能调优,例如,Lock等待表明执行查询存在数据竞争,PageIOLatch等待表明IO响应缓慢,PageLatch等待表明文件的布局需要改进等。
一,查看等待信息
本文分享常用的等待类型及其产生的原因,通常使用DMV来查看等待:
- sys.dm_exec_requests 来查看系统当前正在处理的请求,
- sys.dm_os_wait_stats 统计当前系统发生过的等待的信息
- sys.dm_os_waiting_tasks 查看当前正处于等待状态的task
1,等待信息统计
SQL Server 保存了从上一次服务器启动或者手动清空之后累计的等待信息,总的来说,等待类型分为三类:资源等待,队列等待和外部等待,在日常使用中,通常会过滤掉系统相关的等待类型,因为这些等待对诊断性能瓶颈没有多大用处,同时还过滤掉等待时间为0的类型,脚本见文末的附言。
2,清空等待信息统计
对于生成环境,如果需要收集等待信息,那么最好把等待信息清0,然后重新开始计数,通常使用DBCC SQPERF()命令来实现:
DBCC SQLPERF('sys.dm_os_wait_stats',clear)
二,资源信号(RESOURCE SEMAPHORE)
RESOURCE_SEMAPHORE 等待类型表示一个Workder等待SQL Server给予其申请的内存,以便执行Hash和Sort等操作。
1,RESOURCE_SEMAPHORE 揭示内存压力
当出现 RESOURCE_SEMAPHORE 等待时,这说明查询语句向系统请求的内存没有得到满足,就是说,该查询语句在执行Task前,需要一定量的内存资源,如果SQL Server当前的内存不足,不能分配查询语句请求的内存,将导致查询语句处于等待内存资源的状态。在SQL Server存储引擎中,排序(Sort)操作和哈希(Hash)操作是非常消耗内存资源的两个操作,优化相应的查询语句,以减少这两个操作,可以缓解SQL Server的内存压力,但在SQL Server实例中,经常出现RESOURCE_SEMAPHORE 等待,这说明SQL Server存在内存压力。
在数据库中有一个选项,Min Memory Per Query,该选项表示SQL Server为每个查询分配的最小内存,这意味着,当一个查询需要额外的内存资源,该查询获取的内存大小,很大部分是由该选项决定的,只有为每个查询授予一定的内存之后,该查询语句才会真正开始执行。
2,发送RESOURCE SEMAPHORE用于授予请求内存(Requested Memory)
当SQL Server实例收到用户的查询请求时,SQL Server优化器首先创建编译计划(Complied Plan),根据编译计划再创建执行计划(Execution Plan)。当SQL Server优化器创建编译计划时,它需要计算查询在执行时需要消耗的内存,用于执行查询的内存分为必需内存(Required Memory)和额外内存(Additional Memory)。必需内存是指SQL Server实例执行Sort或Hash操作时必须分配的最小内存,如果没有分配必需内存,查询请求不会执行。额外内存是查询用于存储临时的中间数据的内存,如果SQL Server没有足够的内存,查询将临时数据存储在硬盘中,这会降低查询性能。
SQL Server 要授予每个查询多少内存,查询才能真正开始执行呢?
- Step1,计算需要的内存(Needed Memory):SQL Server计算每个查询需要多少内存才能执行,这通常是必需内存和额外内存之和,当查询请求以并发方式执行时,需要的内存公式是:(RequiredMemory*DOP)+额外内存。
- Step2,计算请求的内存(Requested Memory):SQL Server检查每个查询请求需要的内存数量是否超出系统的限制,SQL Server减少额外内存的数量,以致于不会超出系统的上限,这个最终的内存数量是查询语句得以执行的请求内存。
- Step3,为查询分配请求内存:SQL Server实例发送资源信号(RESOURCE SEMAPHORE),为查询(Query)授予/分配请求的物理内存。
当资源信号发送之后,如果SQL Server实例不能被授予查询的请求内存,那么查询将处于RESOURCE_SEMAPHORE 等待状态。SQL Server维护一个先入先出( first-come-first-served)的等待队列,当新的查询处于RESOURCE_SEMAPHORE 等待状态,SQL Server将该查询放入队列的末尾。一旦SQL Server实例找到足够的空闲内存,那么SQL Server取出RESOURCE_SEMAPHORE 等待队列顶端的第一个查询,立即授予其请求的内存;该查询获得请求内存之后,开始执行查询任务;如果SQL Server实例长时间有查询处于RESOURCE_SEMAPHORE等待状态,说明SQL Server 面临内存压力。
三,调度相关的等待
CXPACKET等待:发生在多任务系统中,用于表示并发执行的子线程在等待其他子线程的完成。
SOS_SCHEDULER_YIELD 等待:当前任务正在执行,但是其主动退让调度程序上的时间片(time slicer),供其他进程使用,自己在后台执行任务。
THREADPOOL 等待:查询正在等待可用的Worker线程,可能出现了大量的并行计划,以至于用完了系统可用的Worker。
DISPATCHER_QUEUE_SEMAPHORE等待:发生当一个进程(Thread)等待处理更多的Work时,也就是说,一个Thread处于空闲状态,等待调度去工作。如果等待时间增加,说明调度器(Dispatcher)非常空闲;该WaitType不会成为竞争资源,而将其他事务阻塞,在做Wait统计分析,可以过滤掉。
四,IO相关的等待
IO相关的等待与IO资源有关,比如,备份和还原等待的等待类型是:BACKUPIO/BACKUPBUFFER,这类等待发生在备份任务正在等待所需的数据或者数据缓存时。
1,异步网络IO(ASYNC_NETWORK_IO)
ASYNC_NETWORK_IO等待类型发生在网络不能及时把数据写入到客户端中。
SQL Server 产生的结果集需要经过网络(Network)传递到客户端(Client),如果网络不能及时将结果集传输到Client,导致结果集仍然驻留在SQL Server的会话(Session)中,就会发生ASYNC_NETWORK_IO 等待,也就是说,ASYNC_NETWORK_IO 等待状态出现在SQL Server已经把数据准备好,但是网络发送速度跟不上,导致SQLServer返回的数据集仍然驻留在Session中,出现这种等待一般不是数据库的问题,调整数据库配置不会有大的帮助,网络层的瓶颈当然是一个可能的原因,对此要考虑是否真有必要返回那么多数据?所以,检查应用程序是否有必要向SQL Server申请这么大的结果集。
This wait type is where SQL Server has sent some data to a client through TDS and is waiting for the client to acknowledge that is has consumed the data, and can also show up with transaction replication if the Log Reader Agent job is running slowly for some reason.
2,异步IO完成(ASYNC_IO_COMPLETION)
ASYNC_IO_COMPLETION:当Task正在等待IO完成时发生,长时间的 ASYNC_IO_COMPLETION 等待经常发生在SQL Server正在执行数据库备份和还原操作(执行Backup database 命令和 Restore 命令)时,查看《ASYNC_IO_COMPLETION》了解更多。
3,同步IO完成(IO_COMPLETION)
同步IO完成,此等待类型发生表示SQL Server正在等待IO操作的完成,通常用于表示非数据页的IO操作,也就是说,文件的各种同步读写操作都与表数据无关,出现该等待,说明SQL Server很有可能正在做下面列出的动作:
- 正在从事务日志文件中读取事务日志
- 正在读取非数据页,可能是管理页(例如,GAM,SGAM,PFS等),经常发生在数据库还原,DB启动和恢复操作中。
- 正在把排序的中间结果集写入到硬盘
- 在Merge Join操作中,正在读写合并的结果集
- 在Eager Spool操作中,正在把数据集写入到硬盘
在发生CXPACKET等待时,如果会话(Session)的数据IO(Logical Read/Write, Physical Read)都没有变化,那么,该会话很可能正在处理非数据页的IO操作。IO_COMPLETION等待通常用于表示非数据页的IO操作,例如,事务日志的还原操作,读取系统数据页(GAM)等。通常来说,减少IO_COMPLETION 等待的方法有两种:一是将IO分散到不同的Physical Disk上,一是减少对非数据页的IO操作。
通常情况下,CXPACKET等待和IO_COMPLETION等待会同时发生,利用 sys.dm_os_waiting_tasks 查看当前处于等待状态的Task,发现有一些Task 处于 IO_COMPLETION 等待,这说明,会话(Session)发生CXPACKET等待,是因为在SQL Server以并行方式执行Task,有一些 Task执行速度慢,有些Task执行速度快,导致执行速度快的task完成之后,等待还未完成的Task;而执行速度慢的Task正在执行非数据页IO。
4,WriteLog(写事务日志到硬盘)
和Disk的写速度有关,说明任务当前正在等待将日志记录写入日志文件,出现这个等待状态,意味着Disk的写入速度是性能瓶颈。
五,Latch等待
Latch是一个轻量级的同步机制,用于在Thread尝试读取或修改数据时,使得Thread之间的数据保持同步。SQL Server共有三种类型的Latch等待:
- PAGEIOLATH_XX:作用于数据页(Data Page),发生在从硬盘读取数据到内存时
- PAGELATCH_XX:作用于已经存在于内存中的数据页(Data Page)
- LATCH_XX:作用于非页(non-page)的数据结构
1,PageIOLatch(硬盘数据页相关的IO)
当缓存在buffer pool 的data page 和disk 上数据文件里的data page 进行交互时,为了保证不会有多个用户同时 read/write 内存中的buffer(a data page in memory),需要对buffer 加上PageIOLatch。PageIOLatch 是和 IO 有关,或从disk将Data page读取到内存,或从内存将Data page写入到disk。
- PageIOLatch主要分为两大类:PageIOLatch_SH和PageIOLatch_EX
- PageIOLatch_SH:发生在将一个Data Page从Disk 读取到内存 buffer pool 中时。当用户需要访问一个Data Page,而这个Data Page不在内存中时,SQL Server 需要将 Data page 从Disk 读取到内存中,这说明内存不够大,或内存紧张,导致没有将Data Page始终缓存在内存中,SQL Server 需要过多地Page Read(从Disk读取Data page到内存 buffer pool)操作。这种情况说明内存是bottleneck。
- PageIOLatch_EX:发生在用户对内存中的Data page进行了修改,SQL Server需要写回Disk,意味着disk的写入速度慢。
2,PageLatch(内存数据页相关的IO)
PageLatch 是对内存中的buffer(a data page in memory)加锁,用于同步内存 buffer Pool中的Data Page数据修改操作。当一个task需要修改 buffer时,必须申请PageLatch_EX。只有得到这个Latch,才能修改buffer里的内存。
由于buffer的修改都是在memory中完成的,所以每次修改的时间都应该非常短,而PageLatch只是在修改的过程中才会短暂出现。如果出现PageLatch等待,说明大量的并发语句在修改table,而修改操作同时集中在同一个page,或者数量不多的几个page上,这些Page 称作Hot Page。出现Hot Page 是由于数据过于集中导致,将数据分布在不同的Files上,能够减少PageLatch Wait。
3,Lacth等待
LATCH等待发生在一个线程整等待访问一个非数据页(Non-Data Page)的结构,该线程无法访问该数据结构,是因为其他的线程正在互斥模式下占用它。
LATCH_EX This wait type occurs when a thread is waiting for access to a non-page data structure so that it can modify the data structure. The thread cannot get access to the data structure because one or more other threads have it latched in share mode. The Latches Whitepaper in the sidebar on the right has a description of all latch modes and their compatibility with other latch modes.
Non-Page的Latch等待对应于LATCH_SH 和 LATCH_EX, sys.dm_os_wait_stats 不会确切显示哪一个Latch是争用点。您可以在sys.dm_os_waiting_tasks DMV中查看实时发生的锁存等待,DMV将显示正在等待的锁存器的名称。 或者,您可以查看sys.dm_os_latch_stats DMV以查看哪些锁存器具有最大的聚合争用。
参考文档:Most common latch classes and what they mean
4,FGCB_ADD_REMOVE闩锁
FGCB代表File Group Control Block,当从文件组中增加或删除文件时,或者当文件组中的文件增长或收缩(file)时,对文件组控制块(FGCB)加闩锁时会出现这类等待。最常发生在文件发生大量的自动增长,也可能来自拥有大量文件的文件组中,例如tempdb的主文件组(Primary FileGroup),当有大量的并发连接需要创建临时表,这会导致tempdb的文件持续不断的增长。对于这类问题,可以做好前期规划,增加文件自动增长的容量,以免频繁增长。
5,ACCESS_METHOD_XX (访问方法)
ACCESS_METHOD_DATASET_PARENT和ACCESS_METHOD_SCAN_RANGE_GENERATOR:发生在并行扫描操作时,在并行扫描期间使用这两个锁存器为每个线程提供一系列要扫描的页面ID,对于这两个等待,应查看是否存在大量扫描和HASH操作。
ACCESS_METHODS_HOBT_COUNT:此锁存器用于将HoBt(Heap或B-Tree)的页和行计数增量刷新到存储引擎元数据表。 争用将指示有大量的,小型并发DML操作作用于单表。
ACCESS_METHOD_HOBT_VIRTUAL_ROOT:通常发生在页的根节点分裂时,此锁存器用于访问包含索引根页面(Root Page)的页面ID(Page ID)的元数据。 当B树的根页面发生分割(需要在EX模式下锁存)时,如果线程想要沿B树向下导航(需要在SH模式下的锁存器)时,那么线程必须等待,此时可能发生对该锁存器的争用。 这种等待可能是由于大量并发连接作用于小索引时出现,或者来自随机键值的页面拆分导致级联页面拆分(从叶子到根)。对于这个等待,应查看是否存在大量页分裂的索引。
六,锁管理器等待(LCK_M_**)
LCK_M_** 等待是Thread正在等待获取锁产生,表明系统产生阻塞问题,一般情况下,是由于编程质量差的查询语句造成的,锁升级,或长时间的IO操作,也会使Task长时间持有锁,产生LCK_M_** 等待。
- LCK_M_IS:当Task正在等待获取意向锁(IS,Intent Shared)时发生
- LCK_M_U:当Task正在等待获取更新锁(U,Update)时发生
附言:下面的脚本用于描述等待的统计数据:
-- Last updated September 25, 2018 WITH [Waits] AS ( SELECT [wait_type], [wait_time_ms] / 1000.0 AS [WaitS], ([wait_time_ms] - [signal_wait_time_ms]) / 1000.0 AS [ResourceS], [signal_wait_time_ms] / 1000.0 AS [SignalS], [waiting_tasks_count] AS [WaitCount], 100.0 * [wait_time_ms] / SUM ([wait_time_ms]) OVER() AS [Percentage], ROW_NUMBER() OVER(ORDER BY [wait_time_ms] DESC) AS [RowNum] FROM sys.dm_os_wait_stats WHERE [wait_type] NOT IN ( -- These wait types are almost 100% never a problem and so they are -- filtered out to avoid them skewing the results. Click on the URL -- for more information. N'BROKER_EVENTHANDLER', -- https://www.sqlskills.com/help/waits/BROKER_EVENTHANDLER N'BROKER_RECEIVE_WAITFOR', -- https://www.sqlskills.com/help/waits/BROKER_RECEIVE_WAITFOR N'BROKER_TASK_STOP', -- https://www.sqlskills.com/help/waits/BROKER_TASK_STOP N'BROKER_TO_FLUSH', -- https://www.sqlskills.com/help/waits/BROKER_TO_FLUSH N'BROKER_TRANSMITTER', -- https://www.sqlskills.com/help/waits/BROKER_TRANSMITTER N'CHECKPOINT_QUEUE', -- https://www.sqlskills.com/help/waits/CHECKPOINT_QUEUE N'CHKPT', -- https://www.sqlskills.com/help/waits/CHKPT N'CLR_AUTO_EVENT', -- https://www.sqlskills.com/help/waits/CLR_AUTO_EVENT N'CLR_MANUAL_EVENT', -- https://www.sqlskills.com/help/waits/CLR_MANUAL_EVENT N'CLR_SEMAPHORE', -- https://www.sqlskills.com/help/waits/CLR_SEMAPHORE N'CXCONSUMER', -- https://www.sqlskills.com/help/waits/CXCONSUMER -- Maybe comment these four out if you have mirroring issues N'DBMIRROR_DBM_EVENT', -- https://www.sqlskills.com/help/waits/DBMIRROR_DBM_EVENT N'DBMIRROR_EVENTS_QUEUE', -- https://www.sqlskills.com/help/waits/DBMIRROR_EVENTS_QUEUE N'DBMIRROR_WORKER_QUEUE', -- https://www.sqlskills.com/help/waits/DBMIRROR_WORKER_QUEUE N'DBMIRRORING_CMD', -- https://www.sqlskills.com/help/waits/DBMIRRORING_CMD N'DIRTY_PAGE_POLL', -- https://www.sqlskills.com/help/waits/DIRTY_PAGE_POLL N'DISPATCHER_QUEUE_SEMAPHORE', -- https://www.sqlskills.com/help/waits/DISPATCHER_QUEUE_SEMAPHORE N'EXECSYNC', -- https://www.sqlskills.com/help/waits/EXECSYNC N'FSAGENT', -- https://www.sqlskills.com/help/waits/FSAGENT N'FT_IFTS_SCHEDULER_IDLE_WAIT', -- https://www.sqlskills.com/help/waits/FT_IFTS_SCHEDULER_IDLE_WAIT N'FT_IFTSHC_MUTEX', -- https://www.sqlskills.com/help/waits/FT_IFTSHC_MUTEX -- Maybe comment these six out if you have AG issues N'HADR_CLUSAPI_CALL', -- https://www.sqlskills.com/help/waits/HADR_CLUSAPI_CALL N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', -- https://www.sqlskills.com/help/waits/HADR_FILESTREAM_IOMGR_IOCOMPLETION N'HADR_LOGCAPTURE_WAIT', -- https://www.sqlskills.com/help/waits/HADR_LOGCAPTURE_WAIT N'HADR_NOTIFICATION_DEQUEUE', -- https://www.sqlskills.com/help/waits/HADR_NOTIFICATION_DEQUEUE N'HADR_TIMER_TASK', -- https://www.sqlskills.com/help/waits/HADR_TIMER_TASK N'HADR_WORK_QUEUE', -- https://www.sqlskills.com/help/waits/HADR_WORK_QUEUE N'KSOURCE_WAKEUP', -- https://www.sqlskills.com/help/waits/KSOURCE_WAKEUP N'LAZYWRITER_SLEEP', -- https://www.sqlskills.com/help/waits/LAZYWRITER_SLEEP N'LOGMGR_QUEUE', -- https://www.sqlskills.com/help/waits/LOGMGR_QUEUE N'MEMORY_ALLOCATION_EXT', -- https://www.sqlskills.com/help/waits/MEMORY_ALLOCATION_EXT N'ONDEMAND_TASK_QUEUE', -- https://www.sqlskills.com/help/waits/ONDEMAND_TASK_QUEUE N'PARALLEL_REDO_DRAIN_WORKER', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_DRAIN_WORKER N'PARALLEL_REDO_LOG_CACHE', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_LOG_CACHE N'PARALLEL_REDO_TRAN_LIST', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_TRAN_LIST N'PARALLEL_REDO_WORKER_SYNC', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_WORKER_SYNC N'PARALLEL_REDO_WORKER_WAIT_WORK', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_WORKER_WAIT_WORK N'PREEMPTIVE_XE_GETTARGETSTATE', -- https://www.sqlskills.com/help/waits/PREEMPTIVE_XE_GETTARGETSTATE N'PWAIT_ALL_COMPONENTS_INITIALIZED', -- https://www.sqlskills.com/help/waits/PWAIT_ALL_COMPONENTS_INITIALIZED N'PWAIT_DIRECTLOGCONSUMER_GETNEXT', -- https://www.sqlskills.com/help/waits/PWAIT_DIRECTLOGCONSUMER_GETNEXT N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP', -- https://www.sqlskills.com/help/waits/QDS_PERSIST_TASK_MAIN_LOOP_SLEEP N'QDS_ASYNC_QUEUE', -- https://www.sqlskills.com/help/waits/QDS_ASYNC_QUEUE N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', -- https://www.sqlskills.com/help/waits/QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP N'QDS_SHUTDOWN_QUEUE', -- https://www.sqlskills.com/help/waits/QDS_SHUTDOWN_QUEUE N'REDO_THREAD_PENDING_WORK', -- https://www.sqlskills.com/help/waits/REDO_THREAD_PENDING_WORK N'REQUEST_FOR_DEADLOCK_SEARCH', -- https://www.sqlskills.com/help/waits/REQUEST_FOR_DEADLOCK_SEARCH N'RESOURCE_QUEUE', -- https://www.sqlskills.com/help/waits/RESOURCE_QUEUE N'SERVER_IDLE_CHECK', -- https://www.sqlskills.com/help/waits/SERVER_IDLE_CHECK N'SLEEP_BPOOL_FLUSH', -- https://www.sqlskills.com/help/waits/SLEEP_BPOOL_FLUSH N'SLEEP_DBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_DBSTARTUP N'SLEEP_DCOMSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_DCOMSTARTUP N'SLEEP_MASTERDBREADY', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERDBREADY N'SLEEP_MASTERMDREADY', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERMDREADY N'SLEEP_MASTERUPGRADED', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERUPGRADED N'SLEEP_MSDBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_MSDBSTARTUP N'SLEEP_SYSTEMTASK', -- https://www.sqlskills.com/help/waits/SLEEP_SYSTEMTASK N'SLEEP_TASK', -- https://www.sqlskills.com/help/waits/SLEEP_TASK N'SLEEP_TEMPDBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_TEMPDBSTARTUP N'SNI_HTTP_ACCEPT', -- https://www.sqlskills.com/help/waits/SNI_HTTP_ACCEPT N'SOS_WORK_DISPATCHER', -- https://www.sqlskills.com/help/waits/SOS_WORK_DISPATCHER N'SP_SERVER_DIAGNOSTICS_SLEEP', -- https://www.sqlskills.com/help/waits/SP_SERVER_DIAGNOSTICS_SLEEP N'SQLTRACE_BUFFER_FLUSH', -- https://www.sqlskills.com/help/waits/SQLTRACE_BUFFER_FLUSH N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', -- https://www.sqlskills.com/help/waits/SQLTRACE_INCREMENTAL_FLUSH_SLEEP N'SQLTRACE_WAIT_ENTRIES', -- https://www.sqlskills.com/help/waits/SQLTRACE_WAIT_ENTRIES N'WAIT_FOR_RESULTS', -- https://www.sqlskills.com/help/waits/WAIT_FOR_RESULTS N'WAITFOR', -- https://www.sqlskills.com/help/waits/WAITFOR N'WAITFOR_TASKSHUTDOWN', -- https://www.sqlskills.com/help/waits/WAITFOR_TASKSHUTDOWN N'WAIT_XTP_RECOVERY', -- https://www.sqlskills.com/help/waits/WAIT_XTP_RECOVERY N'WAIT_XTP_HOST_WAIT', -- https://www.sqlskills.com/help/waits/WAIT_XTP_HOST_WAIT N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', -- https://www.sqlskills.com/help/waits/WAIT_XTP_OFFLINE_CKPT_NEW_LOG N'WAIT_XTP_CKPT_CLOSE', -- https://www.sqlskills.com/help/waits/WAIT_XTP_CKPT_CLOSE N'XE_DISPATCHER_JOIN', -- https://www.sqlskills.com/help/waits/XE_DISPATCHER_JOIN N'XE_DISPATCHER_WAIT', -- https://www.sqlskills.com/help/waits/XE_DISPATCHER_WAIT N'XE_TIMER_EVENT' -- https://www.sqlskills.com/help/waits/XE_TIMER_EVENT ) AND [waiting_tasks_count] > 0 AND [wait_time_ms] > 0 ) SELECT MAX ([W1].[wait_type]) AS [WaitType], CAST (MAX ([W1].[WaitS]) AS DECIMAL (16,2)) AS [Wait_S], CAST (MAX ([W1].[ResourceS]) AS DECIMAL (16,2)) AS [Resource_S], CAST (MAX ([W1].[SignalS]) AS DECIMAL (16,2)) AS [Signal_S], MAX ([W1].[WaitCount]) AS [WaitCount], CAST (MAX ([W1].[Percentage]) AS DECIMAL (5,2)) AS [Percentage], CAST ((MAX ([W1].[WaitS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgWait_S], CAST ((MAX ([W1].[ResourceS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgRes_S], CAST ((MAX ([W1].[SignalS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgSig_S], CAST ('https://www.sqlskills.com/help/waits/' + MAX ([W1].[wait_type]) as XML) AS [Help/Info URL] FROM [Waits] AS [W1] INNER JOIN [Waits] AS [W2] ON [W2].[RowNum] <= [W1].[RowNum] GROUP BY [W1].[RowNum] HAVING SUM ([W2].[Percentage]) - MAX( [W1].[Percentage] ) < 95; -- percentage threshold GO
参考文档:
The SQL Server Wait Type Repository…
Wait statistics, or please tell me where it hurts
Causes of IO_COMPLETION and WRITE_COMPLETION SQL Server wait types
SQL SERVER – IO_COMPLETION – Wait Type – Day 10 of 28
Troubleshooting SQL Server RESOURCE_SEMAPHORE Waittype Memory Issues