Waits and Q's Queries

Print Friendly version

 

Misc Waits and Q's Queries
(mostly using DMVs)
 
Blocking and Head Blocker Queries
 
List Top Wait Types for a Workload

if exists (select * from sys.objects where object_id = object_id(N'[dbo].[get_waitstats_2005]') and OBJECTPROPERTY(object_id, N'IsProcedure') = 1)
	drop procedure [dbo].[get_waitstats_2005]
GO
CREATE proc [dbo].[get_waitstats_2005] (@report_format varchar(20)='all', @report_order varchar(20)='resource')
as

-- this proc will create waitstats report listing wait types by percentage.  
-- 	(1) total wait time is the sum of resource & signal waits, @report_format='all' reports resource & signal
--	(2) Basics of execution model (simplified)
--	    a. spid is running then needs unavailable resource, moves to resource wait list at time T0
--	    b. a signal indicates resource available, spid moves to runnable queue at time T1
--	    c. spid awaits running status until T2 as cpu works its way through runnable queue in order of arrival
--	(3) resource wait time is the actual time waiting for the resource to be available, T1-T0
--	(4) signal wait time is the time it takes from the point the resource is available (T1)
--	      to the point in which the process is running again at T2.  Thus, signal waits are T2-T1
--	(5) Key questions: Are Resource and Signal time significant?
--	    a. Highest waits indicate the bottleneck you need to solve for scalability
--	    b. Generally if you have LOW% SIGNAL WAITS, the CPU is handling the workload e.g. spids spend move through runnable queue quickly
--	    c. HIGH % SIGNAL WAITS indicates CPU can't keep up, significant time for spids to move up the runnable queue to reach running status
-- 	(6) This proc can be run when track_waitstats is executing
-- Revision 4/19/2005
-- (1) add computation for CPU Resource Waits = Sum(signal waits / total waits)
-- (2) add @report_order parm to allow sorting by resource, signal or total waits
set nocount on

declare @now datetime, @totalwait numeric(20,1), @totalsignalwait numeric(20,1), @totalresourcewait numeric(20,1)
	,@endtime datetime,@begintime datetime
	,@hr int, @min int, @sec int

if not exists (select 1 from sysobjects where id = object_id ( N'[dbo].[waitstats]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
begin
		raiserror('Error [dbo].[waitstats] table does not exist', 16, 1) with nowait
		return
end
if lower(@report_format) not in ('all','detail','simple')
	begin
		raiserror ('@report_format must be either ''all'',''detail'', or ''simple''',16,1) with nowait
		return
	end
if lower(@report_order) not in ('resource','signal','total')
	begin
		raiserror ('@report_order must be either ''resource'', ''signal'', or ''total''',16,1) with nowait
		return
	end
if lower(@report_format) = 'simple' and lower(@report_order) <> 'total'
	begin
		raiserror ('@report_format is simple so order defaults to ''total''',16,1) with nowait
		select @report_order = 'total'
	end
select  @now=max(now),@begintime=min(now),@endtime=max(now)
from [dbo].[waitstats] where [wait_type] = 'Total'

--- subtract waitfor, sleep, and resource_queue from Total
select @totalwait = sum([wait_time_ms]) + 1, @totalsignalwait = sum([signal_wait_time_ms]) + 1 from waitstats 
--where [wait_type] not in ('WAITFOR','SLEEP','RESOURCE_QUEUE', 'Total', '***total***') and now = @now
where [wait_type] not in ('CLR_SEMAPHORE','LAZYWRITER_SLEEP','RESOURCE_QUEUE','SLEEP_TASK','SLEEP_SYSTEMTASK','Total','WAITFOR', '***total***') and now = @now
select @totalresourcewait = 1 + @totalwait - @totalsignalwait
-- insert adjusted totals, rank by percentage descending
delete waitstats where [wait_type] = '***total***' and now = @now
insert into waitstats select '***total***',0,@totalwait,0,@totalsignalwait,@now 
select 'start time'=@begintime,'end time'=@endtime
		,'duration (hh:mm:ss:ms)'=convert(varchar(50),@endtime-@begintime,14)
		,'report format'=@report_format, 'report order'=@report_order
if lower(@report_format) in ('all','detail') 
	begin
----- format=detail, column order is resource, signal, total.  order by resource desc
	if lower(@report_order) = 'resource'
	select [wait_type],[waiting_tasks_count]
		,'Resource wt (T1-T0)'=[wait_time_ms]-[signal_wait_time_ms]
		,'res_wt_%'=cast (100*([wait_time_ms] - [signal_wait_time_ms]) /@totalresourcewait as numeric(20,1))
		,'Signal wt (T2-T1)'=[signal_wait_time_ms]
		,'sig_wt_%'=cast (100*[signal_wait_time_ms]/@totalsignalwait as numeric(20,1))
		,'Total wt (T2-T0)'=[wait_time_ms]
		,'wt_%'=cast (100*[wait_time_ms]/@totalwait as numeric(20,1))
	from waitstats 
	where [wait_type] not in ('CLR_SEMAPHORE','LAZYWRITER_SLEEP','RESOURCE_QUEUE','SLEEP_TASK','SLEEP_SYSTEMTASK','Total','WAITFOR')
	and now = @now
	order by 'res_wt_%' desc
----- format=detail, column order signal, resource, total.  order by signal desc
	if lower(@report_order) = 'signal'
	select [wait_type],[waiting_tasks_count]
		,'Signal wt (T2-T1)'=[signal_wait_time_ms]
		,'sig_wt_%'=cast (100*[signal_wait_time_ms]/@totalsignalwait as numeric(20,1))
		,'Resource wt (T1-T0)'=[wait_time_ms]-[signal_wait_time_ms]
		,'res_wt_%'=cast (100*([wait_time_ms] - [signal_wait_time_ms]) /@totalresourcewait as numeric(20,1))
		,'Total wt (T2-T0)'=[wait_time_ms]
		,'wt_%'=cast (100*[wait_time_ms]/@totalwait as numeric(20,1))
	from waitstats 
	where [wait_type] not in ('CLR_SEMAPHORE','LAZYWRITER_SLEEP','RESOURCE_QUEUE','SLEEP_TASK','SLEEP_SYSTEMTASK','Total','WAITFOR')
	and now = @now
	order by 'sig_wt_%' desc
----- format=detail, column order total, resource, signal.  order by total desc
	if lower(@report_order) = 'total'
	select [wait_type],[waiting_tasks_count]
		,'Total wt (T2-T0)'=[wait_time_ms]
		,'wt_%'=cast (100*[wait_time_ms]/@totalwait as numeric(20,1))
		,'Resource wt (T1-T0)'=[wait_time_ms]-[signal_wait_time_ms]
		,'res_wt_%'=cast (100*([wait_time_ms] - [signal_wait_time_ms]) /@totalresourcewait as numeric(20,1))
		,'Signal wt (T2-T1)'=[signal_wait_time_ms]
		,'sig_wt_%'=cast (100*[signal_wait_time_ms]/@totalsignalwait as numeric(20,1))
	from waitstats 
	where [wait_type] not in ('CLR_SEMAPHORE','LAZYWRITER_SLEEP','RESOURCE_QUEUE','SLEEP_TASK','SLEEP_SYSTEMTASK','Total','WAITFOR')
	and now = @now
	order by 'wt_%' desc
end
else
---- simple format, total waits only
	select [wait_type],[wait_time_ms]
			,percentage=cast (100*[wait_time_ms]/@totalwait as numeric(20,1))
	from waitstats 
	where [wait_type] not in ('CLR_SEMAPHORE','LAZYWRITER_SLEEP','RESOURCE_QUEUE','SLEEP_TASK','SLEEP_SYSTEMTASK','Total','WAITFOR')
	and now = @now
	order by percentage desc
---- compute cpu resource waits
select 'total waits'=[wait_time_ms],'total signal=CPU waits'=[signal_wait_time_ms]
	,'CPU resource waits % = signal waits / total waits'=cast (100*[signal_wait_time_ms]/[wait_time_ms] as numeric(20,1)), now
from [dbo].[waitstats]
where [wait_type] = '***total***'
order by now
GO
exec [dbo].[get_waitstats_2005] @report_format='detail',@report_order='resource'

Clearing the Cumulative Wait Stats
DBCC SQLPERF ('sys.dm_os_wait_stats',CLEAR);
 
Top 90 Percent of Wait Time in Database

WITH Waits AS
(SELECT
wait_type
,wait_time_ms/1000 AS wait_time_s,
100*wait_time_ms/sum(wait_time_ms) OVER() as pct
,ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) as row_number
FROM sys.dm_os_wait_stats
WHERE wait_type NOT LIKE '%SLEEP%'
)
SELECT
w1.wait_type
,cast(w1.wait_time_s as decimal(12,2)) as wait_time_s,
cast(w1.pct as deciaml(12,2)) as running_pct
FROM waits as w1
JOIN waits as w2
ON w2.rn <= w1.rn
group by w1.rn, w1.wait_type, w1.wait_time_s,w1.pct
having sum(w2.pct) - w1.pct < 90
order by w1.rn;
Tables and Indexes with the Most Blocks

----Find Row lock waits

declare @dbid int

select @dbid = db_id()

Select dbid=database_id, objectname=object_name(s.object_id)

, indexname=i.name, i.index_id      --, partition_number

, row_lock_count, row_lock_wait_count

, [block %]=cast (100.0 * row_lock_wait_count / (1 + row_lock_count) as numeric(15,2))

, row_lock_wait_in_ms

, [avg row lock waits in ms]=cast (1.0 * row_lock_wait_in_ms / (1 + row_lock_wait_count) as numeric(15,2))

from sys.dm_db_index_operational_stats (@dbid, NULL, NULL, NULL) s,     sys.indexes i

where objectproperty(s.object_id,'IsUserTable') = 1

and i.object_id = s.object_id

and i.index_id = s.index_id

order by row_lock_wait_count desc

 

The average block time is in ms. This must be converted to seconds to properly configure the blocked process threshold parameter. The above query will give you a start if you are not sure where to start with that parameter. You don't want a lot of false positives.

 

 

 
 

Post new comment

The content of this field is kept private and will not be shown publicly.

Syndicate

Syndicate content

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer