文章目录
sys.dm_os_wait_stats 支持诊断 SQL Server 性能问题的基本指标。如果在 SQL Server 引擎中遇到一些问题(CPU、内存、I/O、锁、闩锁等),sys.dm_os_wait_stats 数据揭示一些问题。SQL Server Management Studio 中的活动监视器(activity monitor)包含一个名为“resource waits”的面板。“resource waits”从一个特殊的存储过程中获取这些指标。此临时存储过程名称为“#am_generate_waitstats”,它使用 sys.dm_os_wait_stats视图。可以在“tempdb”中找到此临时存储过程。
临时存储过程与永久存储过程没有区别。它有两种类型:local和global,像临时表。local存储过程在当前会话中保持活动状态,并在会话关闭后被删除。它可以像这样创建:
CREATE PROCEDURE #LocalTestSP
AS
PRINT Hello Local Stored Procedure
global存储过程在所有会话中也保持活动状态,并在创建的会话关闭后删除。可以按如下方式创建全局存储过程:
CREATE PROCEDURE ##GlobalTestSP
AS
PRINT Hello Global Stored Procedure
提示:当我们打开活动监视器时,它会创建#am_generate_waitstats 临时存储过程,并在关闭后将其删除。
以下查询返回 sys.dm_os_wait_stats 的所有等待统计数据,这种查询返回有关从SQLServer startup时间以来的统计信息,由于时间跨度较大,欠缺精准度,无法反映某一时间段的情形
SELECT *
FROM sys.dm_os_wait_stats
ORDER BY wait_time_ms DESC
- wait_type 列:包含等待统计的定义或名称。这列数据非常重要,因为等待统计的定义能够指示问题的主要原因。
- waiting_tasks_count 列:表示 SQL Server 中某种等待类型发生的次数。
- wait_time_ms 列:表示总的等待时间,单位为毫秒。
- max_wait_time_ms 列:表示最大等待时间。
- signal_wait_time_ms 列:MSDN 中定义为“从等待线程收到信号到其开始run的时间差”。当此列值较高时,通常表明存在 CPU 压力。此时查询已进入runnable队列并准备running,但由于 CPU 正忙于处理其他查询,导致查询在队列中等待。当 CPU 资源可用时,会从可运行队列中取出新查询开始处理。简而言之,signal_wait_time_ms 表示查询从“runnable”到“running”状态的等待时间。
提示:在实际应用中,一些等待统计比其他等待更重要,常见的重要等待统计如下:
PAGEIOLATCH_*
• WRITELOG
• ASYNC_NETWORK_IO
• CXPACKET
• CPU
• LCK_M_*
• PREEMPTIVE_*
• PAGELATCH_*
以下资源等待类型可以在 sys.dm_os_wait_stats 查询中消除:
BROKER_EVENTHANDLER
• BROKER_RECEIVE_WAITFOR
• BROKER_TASK_STOP
• BROKER_TO_FLUSH
• BROKER_TRANSMITTER
• CHECKPOINT_QUEUE
• CHKPT
• CLR_AUTO_EVENT
• CLR_MANUAL_EVENT
• CLR_SEMAPHORE
• DBMIRROR_DBM_EVENT
• DBMIRROR_DBM_MUTEX
• DBMIRROR_EVENTS_QUEUE
• DBMIRROR_WORKER_QUEUE
• DBMIRRORING_CMD
• DIRTY_PAGE_POLL
• DISPATCHER_QUEUE_SEMAPHORE
• EXECSYNC
• FSAGENT
• FT_IFTS_SCHEDULER_IDLE_WAIT
• FT_IFTSHC_MUTEX
• HADR_CLUSAPI_CALL
• HADR_FILESTREAM_IOMGR_IOCOMPLETION
• HADR_LOGCAPTURE_WAIT
• HADR_NOTIFICATION_DEQUEUE
• HADR_TIMER_TASK
• HADR_WORK_QUEUE
• LAZYWRITER_SLEEP
• LOGMGR_QUEUE
• MEMORY_ALLOCATION_EXT
• ONDEMAND_TASK_QUEUE
• PREEMPTIVE_HADR_LEASE_MECHANISM
• PREEMPTIVE_OS_AUTHENTICATIONOPS
• PREEMPTIVE_OS_AUTHORIZATIONOPS
• PREEMPTIVE_OS_COMOPS
• PREEMPTIVE_OS_CREATEFILE
• PREEMPTIVE_OS_CRYPTOPS
• PREEMPTIVE_OS_DEVICEOPS
• PREEMPTIVE_OS_FILEOPS
• PREEMPTIVE_OS_GENERICOPS
• PREEMPTIVE_OS_LIBRARYOPS
• PREEMPTIVE_OS_PIPEOPS
• PREEMPTIVE_OS_QUERYREGISTRY
• PREEMPTIVE_OS_VERIFYTRUST
• PREEMPTIVE_OS_WAITFORSINGLEOBJECT
• PREEMPTIVE_OS_WRITEFILEGATHER
• PREEMPTIVE_SP_SERVER_DIAGNOSTICS
• PREEMPTIVE_XE_GETTARGETSTATE
• PWAIT_ALL_COMPONENTS_INITIALIZED
• PWAIT_DIRECTLOGCONSUMER_GETNEXT
• QDS_ASYNC_QUEUE
• QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP
• QDS_PERSIST_TASK_MAIN_LOOP_SLEEP
• QDS_SHUTDOWN_QUEUE
• REDO_THREAD_PENDING_WORK
• REQUEST_FOR_DEADLOCK_SEARCH
• RESOURCE_QUEUE
• SERVER_IDLE_CHECK
• SLEEP_BPOOL_FLUSH
• SLEEP_DBSTARTUP
• SLEEP_DCOMSTARTUP
• SLEEP_MASTERDBREADY
• SLEEP_MASTERMDREADY
• SLEEP_MASTERUPGRADED
• SLEEP_MSDBSTARTUP
• SLEEP_SYSTEMTASK
• SLEEP_TASK
• SP_SERVER_DIAGNOSTICS_SLEEP
• SQLTRACE_BUFFER_FLUSH
• SQLTRACE_INCREMENTAL_FLUSH_SLEEP
• SQLTRACE_WAIT_ENTRIES
• UCS_SESSION_REGISTRATIO
• WAIT_FOR_RESULTS
• WAIT_XTP_CKPT_CLOSE
• WAIT_XTP_HOST_WAIT
• WAIT_XTP_OFFLINE_CKPT_NEW_LOG
• WAIT_XTP_RECOVERY
• WAITFOR
• WAITFOR_TASKSHUTDOW
• XE_TIMER_EVENT
• XE_DISPATCHER_WAIT
• XE_LIVE_TARGET_TVF
提示:SQL Server 在启动或重启时开始收集 DMV 数据。SQL Server 在重启时会自动重置等待统计信息,以下查询强制重置自 SQL Server 上次重启以来的等待统计信息:
DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR)
等待统计的测量精度是关键点,在这一点上可以考虑两种方法:
- 重置等待统计并重新收集数据
- 捕获两个不同时刻的等待统计,并计算它们的差值
个人认为,将等待统计捕获并存储到历史表的方法更优。这种方式可以针对特定的时间区间进行测量,同时保留历史数据的等待统计,不会丢失信息。
接下来,这里将演示如何捕获等待统计,首先,创建一个历史表来存储等待统计:
CREATE TABLE [dbo].[HistoryOfWaitStatistics](
[SQLStartTime] [datetime] NULL,
[Dt] [datetime] NOT NULL,
[WaitType] [nvarchar](60) NOT NULL,
[WaitTimeSecond] [numeric](25, 6) NULL,
[ResourcesWaitSecond] [numeric](25, 6) NULL,
[SignalWaitSecond] [numeric](25, 6) NULL
) ON [PRIMARY]
以下脚本将“等待统计信息”插入到历史记录表中。但需要在 SQL Server Agent 中排程此查询以存储历史记录表:
DROP TABLE IF exists #eliminate_WS
CREATE TABLE #eliminate_WS (wait_type NVARCHAR(100));
INSERT INTO #eliminate_WS VALUES ('ASYNC_IO_COMPLETION');
INSERT INTO #eliminate_WS VALUES ('CHECKPOINT_QUEUE');
INSERT INTO #eliminate_WS VALUES ('CHKPT');
INSERT INTO #eliminate_WS VALUES ('CXPACKET');
INSERT INTO #eliminate_WS VALUES ('DISKIO_SUSPEND');
INSERT INTO #eliminate_WS VALUES ('FT_IFTS_SCHEDULER_IDLE_WAIT');
INSERT INTO #eliminate_WS VALUES ('IO_COMPLETION');
INSERT INTO #eliminate_WS VALUES ('KSOURCE_WAKEUP');
INSERT INTO #eliminate_WS VALUES ('LAZYWRITER_SLEEP');
INSERT INTO #eliminate_WS VALUES ('LOGBUFFER');
INSERT INTO #eliminate_WS VALUES ('LOGMGR_QUEUE');
INSERT INTO #eliminate_WS VALUES ('MISCELLANEOUS');
INSERT INTO #eliminate_WS VALUES ('PREEMPTIVE_XXX');
INSERT INTO #eliminate_WS VALUES ('REQUEST_FOR_DEADLOCK_SEARCH');
INSERT INTO #eliminate_WS VALUES ('RESOURCE_QUERY_SEMAPHORE_COMPILE');
INSERT INTO #eliminate_WS VALUES ('RESOURCE_SEMAPHORE');
INSERT INTO #eliminate_WS VALUES ('SOS_SCHEDULER_YIELD');
INSERT INTO #eliminate_WS VALUES ('SQLTRACE_BUFFER_FLUSH ');
INSERT INTO #eliminate_WS VALUES ('THREADPOOL');
INSERT INTO #eliminate_WS VALUES ('WRITELOG');
INSERT INTO #eliminate_WS VALUES ('XE_DISPATCHER_WAIT');
INSERT INTO #eliminate_WS VALUES ('XE_TIMER_EVENT');INSERT INTO HistoryOfWaitStatistics
SELECT
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info ) as SQLStartTime,GETDATE() AS Dt,Wait_type as WaitType,
wait_time_ms / 1000. AS WaitTimeSecond,(wait_time_ms - signal_wait_time_ms)/1000. AS ResourcesWaitSecond,
signal_wait_time_ms/1000. AS SignalWaitSecond
FROM sys.dm_os_wait_stats
WHERE wait_type IN(SELECT wait_type FROM #eliminate_WS)
存储历史数据后,可以针对某个时间段的统计信息进行聚合,获取想要的资讯