· 7 years ago · Nov 07, 2018, 12:32 AM
1----------------------------------------------------------------------------------------------------
2-- !!!!!SQL Always/Never Fix script. REVIEW ALL SETTINGS BEFORE RUNNING. If in doubt ask!!!!!
3-- v1 (2015-08-19) Updated by Greg Cecil. Originally compiled by Craig Ryan.
4----------------------------------------------------------------------------------------------------
5set nocount on;
6use master;
7go
8-- Turn on "advanced options", so that settings can be changed if need be
9if exists (select * from sys.configurations where name = 'show advanced options' and value_in_use = 0)
10 exec sys.sp_configure 'show advanced options', 1 reconfigure with override
11go
12-----------------------------------------------------
13-----------------------------------------------------
14-- !!! MAXIMUM DEGREE OF PARALLELISM Set the server specific value here: see https://support.microsoft.com/en-us/kb/2806535. http://www.brentozar.com/archive/2013/09/five-sql-server-settings-to-change/
15-----------------------------------------------------
16-- Never set this to 1.
17-- SQL Express? Set to 4. See https://msdn.microsoft.com/library/cc645993.aspx
18-- Never set this higher than the number of cores per socket
19if exists (select * from sys.configurations where name = 'max degree of parallelism' and value_in_use = 0)
20 exec sys.sp_configure 'max degree of parallelism', 4 reconfigure with override
21go
22-----------------------------------------------------
23-----------------------------------------------------
24-- !!! Set to system RAM less the amount we need for Windows and other apps.
25-----------------------------------------------------
26-----------------------------------------------------
27-- Suggested values
28-- This assumes there is a single SQL Instance running on the host server.
29-- 11500 for 16GB RAM servers
30-- 26500 for 32GB RAM servers
31-- 54000 for 64GB RAM servers
32if exists (select * from sys.configurations where name = 'max server memory (MB)' and value_in_use = 2147483647)
33 exec sys.sp_configure 'max server memory (MB)', 11500 reconfigure with override
34go
35-----------------------------------------------------
36-- SQL Server Configuration Options
37-----------------------------------------------------
38-- Turn on backup compression by default
39if exists (select * from sys.configurations where name = 'backup compression default' and value_in_use = 0)
40 exec sys.sp_configure 'backup compression default', 1 reconfigure with override
41go
42-- Cost threshold for parallelism
43if exists (select * from sys.configurations where name = 'cost threshold for parallelism' and value_in_use = 5)
44 exec sys.sp_configure 'cost threshold for parallelism', 80 reconfigure with override
45go
46-- Enable Optimize for ad hoc workloads
47if exists (select * from sys.configurations where name = 'optimize for ad hoc workloads' and value_in_use = 0)
48 exec sys.sp_configure 'optimize for ad hoc workloads', 1 reconfigure with override
49go
50-- Disable Priority boost
51if exists (select * from sys.configurations where name = 'priority boost' and value_in_use = 1)
52 exec sys.sp_configure 'priority boost', 0 reconfigure with override
53go
54-- Enable DAC
55if exists (select * from sys.configurations where name = 'remote admin connections' and value_in_use = 0)
56 exec sys.sp_configure 'remote admin connections', 1 reconfigure with override
57go
58-----------------------------------------------------
59-- SQL Server Trace Flags
60-----------------------------------------------------
61use master
62go
63-- Only create this SP if it doesn't exist. Customise for each server
64if not exists (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[upEnableTraceFlags]') AND type in (N'P', N'PC'))
65 begin
66 declare @cmd nvarchar(max)
67
68 select @cmd = 'create procedure dbo.upEnableTraceFlags
69 as
70 set nocount on;
71 dbcc traceon(4199, -1); -- enable Query optimiser fixes. KB974006. Not required in SQL 2014
72 dbcc traceon(3226, -1); -- Suppress successful backup operations being written to errorlog (BOL)
73 dbcc traceon(1118, -1); -- Directs SQL to allocate full extents to each tempdb object. Less contention. KB328551 & KB936185
74 dbcc traceon(1117, -1); -- Auto grow files by same amount
75 dbcc traceon(2371, -1); -- Auto update stats more often'
76
77 exec sp_executesql @cmd
78
79 exec sp_procoption 'upEnableTraceFlags', 'Startup', 'on'
80
81 end
82go
83exec dbo.upEnableTraceFlags
84go
85----------------------------------------------------------------------------------------------
86-- Turn off AUTO-SHRINK
87----------------------------------------------------------------------------------------------
88declare @Counter int = 1
89 , @RowCount int
90 , @DB sysname
91 , @SQLCmd varchar(2000)
92
93if (select object_id('tempdb..#autoshrink')) is not null
94 drop table #AutoShrink
95
96create table #AutoShrink
97 ( AutoShrinkID int identity(1,1) not null primary key
98 , DBName sysname not null
99 )
100
101insert #AutoShrink (DBName)
102 select name
103 from sys.databases
104 where is_auto_shrink_on = 1
105
106select @RowCount = @@rowcount
107
108while @Counter <= @RowCount
109 begin
110 select @DB = DBName
111 from #AutoShrink
112 where AutoShrinkID = @Counter
113
114 select @SQLCmd = 'ALTER DATABASE [' + @db + '] SET AUTO_SHRINK OFF WITH NO_WAIT'
115 exec (@SQLCmd)
116
117 print 'Turned off Auto-Shrink on ' + @db
118 select @Counter = @Counter + 1
119 end
120go
121----------------------------------------------------------------------------------------------
122-- Turn off AUTO-CLOSE
123----------------------------------------------------------------------------------------------
124declare @Counter int = 1
125 , @RowCount int
126 , @DB sysname
127 , @SQLCmd varchar(2000)
128
129if (select object_id('tempdb..#AutoClose')) is not null
130 drop table #AutoClose
131
132create table #AutoClose
133 ( AutoCloseID int identity(1,1) not null primary key
134 , DBName sysname not null
135 )
136
137insert #AutoClose (DBName)
138 select name
139 from sys.databases
140 where is_auto_close_on = 1
141
142select @RowCount = @@rowcount
143
144while @Counter <= @RowCount
145 begin
146 select @DB = DBName
147 from #AutoClose
148 where AutoCloseID = @Counter
149
150 select @SQLCmd = 'ALTER DATABASE [' + @db + '] SET AUTO_CLOSE OFF WITH NO_WAIT'
151 exec (@SQLCmd)
152
153 print 'Turned off Auto-Close on ' + @db
154 select @Counter = @Counter + 1
155 end
156go
157----------------------------------------------------------------------------------------------
158-- Turn on AUTO-Create Stats
159----------------------------------------------------------------------------------------------
160declare @Counter int = 1
161 , @RowCount int
162 , @DB sysname
163 , @SQLCmd varchar(2000)
164
165if (select object_id('tempdb..#AutoCreateStats')) is not null
166 drop table #AutoCreateStats
167
168create table #AutoCreateStats
169 ( AutoCreateStatsID int identity(1,1) not null primary key
170 , DBName sysname not null
171 )
172
173insert #AutoCreateStats (DBName)
174 select name
175 from sys.databases
176 where is_auto_create_stats_on = 0
177
178select @RowCount = @@rowcount
179
180while @Counter <= @RowCount
181 begin
182 select @DB = DBName
183 from #AutoCreateStats
184 where AutoCreateStatsID = @Counter
185
186 select @SQLCmd = 'ALTER DATABASE [' + @db + '] SET AUTO_CREATE_STATISTICS ON WITH NO_WAIT'
187 exec (@SQLCmd)
188
189 print 'Turned on Auto Create Stats on ' + @db
190 select @Counter = @Counter + 1
191 end
192
193go
194----------------------------------------------------------------------------------------------
195-- Turn on AUTO-Update stats
196----------------------------------------------------------------------------------------------
197declare @Counter int = 1
198 , @RowCount int
199 , @DB sysname
200 , @SQLCmd varchar(2000)
201
202if (select object_id('tempdb..#AutoUpdateStats')) is not null
203 drop table #AutoUpdateStats
204
205create table #AutoUpdateStats
206 ( AutoUpdateStatsID int identity(1,1) not null primary key
207 , DBName sysname not null
208 )
209
210insert #AutoUpdateStats (DBName)
211 select name
212 from sys.databases
213 where is_auto_update_stats_on = 0
214
215select @RowCount = @@rowcount
216
217while @Counter <= @RowCount
218 begin
219 select @DB = DBName
220 from #AutoUpdateStats
221 where AutoUpdateStatsID = @Counter
222
223 select @SQLCmd = 'ALTER DATABASE [' + @db + '] SET AUTO_UPDATE_STATISTICS ON WITH NO_WAIT'
224 exec (@SQLCmd)
225
226 print 'Turned on Auto Update Stats on ' + @db
227 select @Counter = @Counter + 1
228 end
229
230go
231----------------------------------------------------------------------------------------------
232-- Make safe settings on model db
233----------------------------------------------------------------------------------------------
234USE [master]
235GO
236ALTER DATABASE [model] SET RECOVERY SIMPLE WITH NO_WAIT
237GO
238ALTER DATABASE [model] MODIFY FILE ( NAME = N'modeldev', SIZE = 524288KB , FILEGROWTH = 524288KB )
239GO
240ALTER DATABASE [model] MODIFY FILE ( NAME = N'modellog', SIZE = 524288KB , FILEGROWTH = 524288KB )
241GO
242----------------------------------------------------------------------------------------------
243-- Change file size and auto-growth to 512MB
244----------------------------------------------------------------------------------------------
245declare @Counter int = 1
246 , @RowCount int
247 , @DB sysname
248 , @LogicalName sysname
249 , @IsPercent bit
250 , @Growth int
251 , @SQLCmd varchar(2000)
252
253if (select object_id('tempdb..#DBFile')) is not null
254 drop table #DBFile
255
256create table #DBFile
257 ( DBFileID int identity(1,1) not null primary key
258 , DBName sysname not null
259 , LogicalFileName sysname not null
260 )
261
262insert #DBFile (DBName, LogicalFileName)
263 select substring(db_name([database_id]), 1, 100) as 'Database Name'
264 , name as 'DatabaseLogicalFilename'
265 from sys.master_files
266 where [database_id] > 4
267 and [database_id] <> 32767
268 and state_desc = 'ONLINE'
269 and ( is_percent_growth = 1
270 or growth < 10000 -- pages
271 )
272 option (recompile);
273
274select @RowCount = @@rowcount
275
276while @Counter <= @RowCount
277 begin
278 select @DB = DBName
279 , @LogicalName = LogicalFileName
280 from #DBFile
281 where DBFileID = @Counter
282
283 select @SQLCmd = 'ALTER DATABASE [' + @db + '] MODIFY FILE ( NAME = N''' + @LogicalName + ''', SIZE = 524288KB)
284 ALTER DATABASE [' + @db + '] MODIFY FILE ( NAME = N''' + @LogicalName + ''', FILEGROWTH = 524288KB) '
285 print @SQLCmd -- just FYI
286 exec (@SQLCmd)
287
288 select @Counter = @Counter + 1
289 end
290go
291----------------------------------------------------------------------------------------------
292-- Fix the Compatibility mode
293----------------------------------------------------------------------------------------------
294declare @Counter int = 1
295 , @RowCount int
296 , @DB sysname
297 , @SQLCmd varchar(2000)
298 , @MasterCompat tinyint
299
300select @MasterCompat = [compatibility_level]
301from sys.databases
302where database_id = 1
303
304if (select object_id('tempdb..#Compat')) is not null
305 drop table #Compat
306
307create table #Compat
308 ( CompatID int identity(1,1) not null primary key
309 , DBName sysname not null
310 )
311
312insert #Compat (DBName)
313 select name
314 from sys.databases
315 where compatibility_level <> @MasterCompat
316
317select @RowCount = @@rowcount
318
319while @Counter <= @RowCount
320 begin
321 select @DB = DBName
322 from #Compat
323 where CompatID = @Counter
324
325 select @SQLCmd = 'ALTER DATABASE [' + @db + '] set COMPATIBILITY_LEVEL = ' + convert(varchar, @MasterCompat)
326 print @SQLCmd
327 exec (@SQLCmd)
328
329 select @Counter = @Counter + 1
330 end
331go
332----------------------------------------------------------------------------------------------
333-- Fix the Page Verify mode
334----------------------------------------------------------------------------------------------
335declare @Counter int = 1
336 , @RowCount int
337 , @DB sysname
338 , @SQLCmd varchar(2000)
339
340if (select object_id('tempdb..#PageVerify')) is not null
341 drop table #PageVerify
342
343create table #PageVerify
344 ( PageVerifyID int identity(1,1) not null primary key
345 , DBName sysname not null
346 )
347
348insert #PageVerify (DBName)
349 select name
350 from sys.databases
351 where page_verify_option_desc <> 'CHECKSUM'
352
353select @RowCount = @@rowcount
354
355while @Counter <= @RowCount
356 begin
357 select @DB = DBName
358 from #PageVerify
359 where PageVerifyID = @Counter
360
361 select @SQLCmd = 'ALTER DATABASE [' + @db + '] SET PAGE_VERIFY CHECKSUM WITH NO_WAIT'
362 print @SQLCmd
363 exec (@SQLCmd)
364
365 -- need to touch every page for this to take effect, best way it to rebuild all indexes
366 exec sp_msforeachtable 'set QUOTED_IDENTIFIER on alter index all on ? rebuild'
367
368 select @Counter = @Counter + 1
369 end
370go
371----------------------------------------------------------------------------------------------
372-- Install SP_WhoIsActive http://sqlblog.com/blogs/adam_machanic/archive/2012/03/22/released-who-is-active-v11-11.aspx
373----------------------------------------------------------------------------------------------
374IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'sp_WhoIsActive')
375 EXEC ('CREATE PROC dbo.sp_WhoIsActive AS SELECT ''stub version, to be replaced''')
376GO
377
378/*********************************************************************************************
379Who Is Active? v11.11 (2012-03-22)
380(C) 2007-2012, Adam Machanic
381
382Feedback: mailto:amachanic@gmail.com
383Updates: http://sqlblog.com/blogs/adam_machanic/archive/tags/who+is+active/default.aspx
384"Beta" Builds: http://sqlblog.com/files/folders/beta/tags/who+is+active/default.aspx
385
386Donate! Support this project: http://tinyurl.com/WhoIsActiveDonate
387
388License:
389 Who is Active? is free to download and use for personal, educational, and internal
390 corporate purposes, provided that this header is preserved. Redistribution or sale
391 of Who is Active?, in whole or in part, is prohibited without the author's express
392 written consent.
393*********************************************************************************************/
394ALTER PROC dbo.sp_WhoIsActive
395(
396--~
397 --Filters--Both inclusive and exclusive
398 --Set either filter to '' to disable
399 --Valid filter types are: session, program, database, login, and host
400 --Session is a session ID, and either 0 or '' can be used to indicate "all" sessions
401 --All other filter types support % or _ as wildcards
402 @filter sysname = '',
403 @filter_type VARCHAR(10) = 'session',
404 @not_filter sysname = '',
405 @not_filter_type VARCHAR(10) = 'session',
406
407 --Retrieve data about the calling session?
408 @show_own_spid BIT = 0,
409
410 --Retrieve data about system sessions?
411 @show_system_spids BIT = 0,
412
413 --Controls how sleeping SPIDs are handled, based on the idea of levels of interest
414 --0 does not pull any sleeping SPIDs
415 --1 pulls only those sleeping SPIDs that also have an open transaction
416 --2 pulls all sleeping SPIDs
417 @show_sleeping_spids TINYINT = 1,
418
419 --If 1, gets the full stored procedure or running batch, when available
420 --If 0, gets only the actual statement that is currently running in the batch or procedure
421 @get_full_inner_text BIT = 0,
422
423 --Get associated query plans for running tasks, if available
424 --If @get_plans = 1, gets the plan based on the request's statement offset
425 --If @get_plans = 2, gets the entire plan based on the request's plan_handle
426 @get_plans TINYINT = 0,
427
428 --Get the associated outer ad hoc query or stored procedure call, if available
429 @get_outer_command BIT = 0,
430
431 --Enables pulling transaction log write info and transaction duration
432 @get_transaction_info BIT = 0,
433
434 --Get information on active tasks, based on three interest levels
435 --Level 0 does not pull any task-related information
436 --Level 1 is a lightweight mode that pulls the top non-CXPACKET wait, giving preference to blockers
437 --Level 2 pulls all available task-based metrics, including:
438 --number of active tasks, current wait stats, physical I/O, context switches, and blocker information
439 @get_task_info TINYINT = 1,
440
441 --Gets associated locks for each request, aggregated in an XML format
442 @get_locks BIT = 0,
443
444 --Get average time for past runs of an active query
445 --(based on the combination of plan handle, sql handle, and offset)
446 @get_avg_time BIT = 0,
447
448 --Get additional non-performance-related information about the session or request
449 --text_size, language, date_format, date_first, quoted_identifier, arithabort, ansi_null_dflt_on,
450 --ansi_defaults, ansi_warnings, ansi_padding, ansi_nulls, concat_null_yields_null,
451 --transaction_isolation_level, lock_timeout, deadlock_priority, row_count, command_type
452 --
453 --If a SQL Agent job is running, an subnode called agent_info will be populated with some or all of
454 --the following: job_id, job_name, step_id, step_name, msdb_query_error (in the event of an error)
455 --
456 --If @get_task_info is set to 2 and a lock wait is detected, a subnode called block_info will be
457 --populated with some or all of the following: lock_type, database_name, object_id, file_id, hobt_id,
458 --applock_hash, metadata_resource, metadata_class_id, object_name, schema_name
459 @get_additional_info BIT = 0,
460
461 --Walk the blocking chain and count the number of
462 --total SPIDs blocked all the way down by a given session
463 --Also enables task_info Level 1, if @get_task_info is set to 0
464 @find_block_leaders BIT = 0,
465
466 --Pull deltas on various metrics
467 --Interval in seconds to wait before doing the second data pull
468 @delta_interval TINYINT = 0,
469
470 --List of desired output columns, in desired order
471 --Note that the final output will be the intersection of all enabled features and all
472 --columns in the list. Therefore, only columns associated with enabled features will
473 --actually appear in the output. Likewise, removing columns from this list may effectively
474 --disable features, even if they are turned on
475 --
476 --Each element in this list must be one of the valid output column names. Names must be
477 --delimited by square brackets. White space, formatting, and additional characters are
478 --allowed, as long as the list contains exact matches of delimited valid column names.
479 @output_column_list VARCHAR(8000) = '[dd%][session_id][sql_text][sql_command][login_name][wait_info][tasks][tran_log%][cpu%][temp%][block%][reads%][writes%][context%][physical%][query_plan][locks][%]',
480
481 --Column(s) by which to sort output, optionally with sort directions.
482 --Valid column choices:
483 --session_id, physical_io, reads, physical_reads, writes, tempdb_allocations,
484 --tempdb_current, CPU, context_switches, used_memory, physical_io_delta,
485 --reads_delta, physical_reads_delta, writes_delta, tempdb_allocations_delta,
486 --tempdb_current_delta, CPU_delta, context_switches_delta, used_memory_delta,
487 --tasks, tran_start_time, open_tran_count, blocking_session_id, blocked_session_count,
488 --percent_complete, host_name, login_name, database_name, start_time, login_time
489 --
490 --Note that column names in the list must be bracket-delimited. Commas and/or white
491 --space are not required.
492 @sort_order VARCHAR(500) = '[start_time] ASC',
493
494 --Formats some of the output columns in a more "human readable" form
495 --0 disables outfput format
496 --1 formats the output for variable-width fonts
497 --2 formats the output for fixed-width fonts
498 @format_output TINYINT = 1,
499
500 --If set to a non-blank value, the script will attempt to insert into the specified
501 --destination table. Please note that the script will not verify that the table exists,
502 --or that it has the correct schema, before doing the insert.
503 --Table can be specified in one, two, or three-part format
504 @destination_table VARCHAR(4000) = '',
505
506 --If set to 1, no data collection will happen and no result set will be returned; instead,
507 --a CREATE TABLE statement will be returned via the @schema parameter, which will match
508 --the schema of the result set that would be returned by using the same collection of the
509 --rest of the parameters. The CREATE TABLE statement will have a placeholder token of
510 --<table_name> in place of an actual table name.
511 @return_schema BIT = 0,
512 @schema VARCHAR(MAX) = NULL OUTPUT,
513
514 --Help! What do I do?
515 @help BIT = 0
516--~
517)
518/*
519OUTPUT COLUMNS
520--------------
521Formatted/Non: [session_id] [smallint] NOT NULL
522 Session ID (a.k.a. SPID)
523
524Formatted: [dd hh:mm:ss.mss] [varchar](15) NULL
525Non-Formatted: <not returned>
526 For an active request, time the query has been running
527 For a sleeping session, time since the last batch completed
528
529Formatted: [dd hh:mm:ss.mss (avg)] [varchar](15) NULL
530Non-Formatted: [avg_elapsed_time] [int] NULL
531 (Requires @get_avg_time option)
532 How much time has the active portion of the query taken in the past, on average?
533
534Formatted: [physical_io] [varchar](30) NULL
535Non-Formatted: [physical_io] [bigint] NULL
536 Shows the number of physical I/Os, for active requests
537
538Formatted: [reads] [varchar](30) NULL
539Non-Formatted: [reads] [bigint] NULL
540 For an active request, number of reads done for the current query
541 For a sleeping session, total number of reads done over the lifetime of the session
542
543Formatted: [physical_reads] [varchar](30) NULL
544Non-Formatted: [physical_reads] [bigint] NULL
545 For an active request, number of physical reads done for the current query
546 For a sleeping session, total number of physical reads done over the lifetime of the session
547
548Formatted: [writes] [varchar](30) NULL
549Non-Formatted: [writes] [bigint] NULL
550 For an active request, number of writes done for the current query
551 For a sleeping session, total number of writes done over the lifetime of the session
552
553Formatted: [tempdb_allocations] [varchar](30) NULL
554Non-Formatted: [tempdb_allocations] [bigint] NULL
555 For an active request, number of TempDB writes done for the current query
556 For a sleeping session, total number of TempDB writes done over the lifetime of the session
557
558Formatted: [tempdb_current] [varchar](30) NULL
559Non-Formatted: [tempdb_current] [bigint] NULL
560 For an active request, number of TempDB pages currently allocated for the query
561 For a sleeping session, number of TempDB pages currently allocated for the session
562
563Formatted: [CPU] [varchar](30) NULL
564Non-Formatted: [CPU] [int] NULL
565 For an active request, total CPU time consumed by the current query
566 For a sleeping session, total CPU time consumed over the lifetime of the session
567
568Formatted: [context_switches] [varchar](30) NULL
569Non-Formatted: [context_switches] [bigint] NULL
570 Shows the number of context switches, for active requests
571
572Formatted: [used_memory] [varchar](30) NOT NULL
573Non-Formatted: [used_memory] [bigint] NOT NULL
574 For an active request, total memory consumption for the current query
575 For a sleeping session, total current memory consumption
576
577Formatted: [physical_io_delta] [varchar](30) NULL
578Non-Formatted: [physical_io_delta] [bigint] NULL
579 (Requires @delta_interval option)
580 Difference between the number of physical I/Os reported on the first and second collections.
581 If the request started after the first collection, the value will be NULL
582
583Formatted: [reads_delta] [varchar](30) NULL
584Non-Formatted: [reads_delta] [bigint] NULL
585 (Requires @delta_interval option)
586 Difference between the number of reads reported on the first and second collections.
587 If the request started after the first collection, the value will be NULL
588
589Formatted: [physical_reads_delta] [varchar](30) NULL
590Non-Formatted: [physical_reads_delta] [bigint] NULL
591 (Requires @delta_interval option)
592 Difference between the number of physical reads reported on the first and second collections.
593 If the request started after the first collection, the value will be NULL
594
595Formatted: [writes_delta] [varchar](30) NULL
596Non-Formatted: [writes_delta] [bigint] NULL
597 (Requires @delta_interval option)
598 Difference between the number of writes reported on the first and second collections.
599 If the request started after the first collection, the value will be NULL
600
601Formatted: [tempdb_allocations_delta] [varchar](30) NULL
602Non-Formatted: [tempdb_allocations_delta] [bigint] NULL
603 (Requires @delta_interval option)
604 Difference between the number of TempDB writes reported on the first and second collections.
605 If the request started after the first collection, the value will be NULL
606
607Formatted: [tempdb_current_delta] [varchar](30) NULL
608Non-Formatted: [tempdb_current_delta] [bigint] NULL
609 (Requires @delta_interval option)
610 Difference between the number of allocated TempDB pages reported on the first and second
611 collections. If the request started after the first collection, the value will be NULL
612
613Formatted: [CPU_delta] [varchar](30) NULL
614Non-Formatted: [CPU_delta] [int] NULL
615 (Requires @delta_interval option)
616 Difference between the CPU time reported on the first and second collections.
617 If the request started after the first collection, the value will be NULL
618
619Formatted: [context_switches_delta] [varchar](30) NULL
620Non-Formatted: [context_switches_delta] [bigint] NULL
621 (Requires @delta_interval option)
622 Difference between the context switches count reported on the first and second collections
623 If the request started after the first collection, the value will be NULL
624
625Formatted: [used_memory_delta] [varchar](30) NULL
626Non-Formatted: [used_memory_delta] [bigint] NULL
627 Difference between the memory usage reported on the first and second collections
628 If the request started after the first collection, the value will be NULL
629
630Formatted: [tasks] [varchar](30) NULL
631Non-Formatted: [tasks] [smallint] NULL
632 Number of worker tasks currently allocated, for active requests
633
634Formatted/Non: [status] [varchar](30) NOT NULL
635 Activity status for the session (running, sleeping, etc)
636
637Formatted/Non: [wait_info] [nvarchar](4000) NULL
638 Aggregates wait information, in the following format:
639 (Ax: Bms/Cms/Dms)E
640 A is the number of waiting tasks currently waiting on resource type E. B/C/D are wait
641 times, in milliseconds. If only one thread is waiting, its wait time will be shown as B.
642 If two tasks are waiting, each of their wait times will be shown (B/C). If three or more
643 tasks are waiting, the minimum, average, and maximum wait times will be shown (B/C/D).
644 If wait type E is a page latch wait and the page is of a "special" type (e.g. PFS, GAM, SGAM),
645 the page type will be identified.
646 If wait type E is CXPACKET, the nodeId from the query plan will be identified
647
648Formatted/Non: [locks] [xml] NULL
649 (Requires @get_locks option)
650 Aggregates lock information, in XML format.
651 The lock XML includes the lock mode, locked object, and aggregates the number of requests.
652 Attempts are made to identify locked objects by name
653
654Formatted/Non: [tran_start_time] [datetime] NULL
655 (Requires @get_transaction_info option)
656 Date and time that the first transaction opened by a session caused a transaction log
657 write to occur.
658
659Formatted/Non: [tran_log_writes] [nvarchar](4000) NULL
660 (Requires @get_transaction_info option)
661 Aggregates transaction log write information, in the following format:
662 A:wB (C kB)
663 A is a database that has been touched by an active transaction
664 B is the number of log writes that have been made in the database as a result of the transaction
665 C is the number of log kilobytes consumed by the log records
666
667Formatted: [open_tran_count] [varchar](30) NULL
668Non-Formatted: [open_tran_count] [smallint] NULL
669 Shows the number of open transactions the session has open
670
671Formatted: [sql_command] [xml] NULL
672Non-Formatted: [sql_command] [nvarchar](max) NULL
673 (Requires @get_outer_command option)
674 Shows the "outer" SQL command, i.e. the text of the batch or RPC sent to the server,
675 if available
676
677Formatted: [sql_text] [xml] NULL
678Non-Formatted: [sql_text] [nvarchar](max) NULL
679 Shows the SQL text for active requests or the last statement executed
680 for sleeping sessions, if available in either case.
681 If @get_full_inner_text option is set, shows the full text of the batch.
682 Otherwise, shows only the active statement within the batch.
683 If the query text is locked, a special timeout message will be sent, in the following format:
684 <timeout_exceeded />
685 If an error occurs, an error message will be sent, in the following format:
686 <error message="message" />
687
688Formatted/Non: [query_plan] [xml] NULL
689 (Requires @get_plans option)
690 Shows the query plan for the request, if available.
691 If the plan is locked, a special timeout message will be sent, in the following format:
692 <timeout_exceeded />
693 If an error occurs, an error message will be sent, in the following format:
694 <error message="message" />
695
696Formatted/Non: [blocking_session_id] [smallint] NULL
697 When applicable, shows the blocking SPID
698
699Formatted: [blocked_session_count] [varchar](30) NULL
700Non-Formatted: [blocked_session_count] [smallint] NULL
701 (Requires @find_block_leaders option)
702 The total number of SPIDs blocked by this session,
703 all the way down the blocking chain.
704
705Formatted: [percent_complete] [varchar](30) NULL
706Non-Formatted: [percent_complete] [real] NULL
707 When applicable, shows the percent complete (e.g. for backups, restores, and some rollbacks)
708
709Formatted/Non: [host_name] [sysname] NOT NULL
710 Shows the host name for the connection
711
712Formatted/Non: [login_name] [sysname] NOT NULL
713 Shows the login name for the connection
714
715Formatted/Non: [database_name] [sysname] NULL
716 Shows the connected database
717
718Formatted/Non: [program_name] [sysname] NULL
719 Shows the reported program/application name
720
721Formatted/Non: [additional_info] [xml] NULL
722 (Requires @get_additional_info option)
723 Returns additional non-performance-related session/request information
724 If the script finds a SQL Agent job running, the name of the job and job step will be reported
725 If @get_task_info = 2 and the script finds a lock wait, the locked object will be reported
726
727Formatted/Non: [start_time] [datetime] NOT NULL
728 For active requests, shows the time the request started
729 For sleeping sessions, shows the time the last batch completed
730
731Formatted/Non: [login_time] [datetime] NOT NULL
732 Shows the time that the session connected
733
734Formatted/Non: [request_id] [int] NULL
735 For active requests, shows the request_id
736 Should be 0 unless MARS is being used
737
738Formatted/Non: [collection_time] [datetime] NOT NULL
739 Time that this script's final SELECT ran
740*/
741AS
742BEGIN;
743 SET NOCOUNT ON;
744 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
745 SET QUOTED_IDENTIFIER ON;
746 SET ANSI_PADDING ON;
747 SET CONCAT_NULL_YIELDS_NULL ON;
748 SET ANSI_WARNINGS ON;
749 SET NUMERIC_ROUNDABORT OFF;
750 SET ARITHABORT ON;
751
752 IF
753 @filter IS NULL
754 OR @filter_type IS NULL
755 OR @not_filter IS NULL
756 OR @not_filter_type IS NULL
757 OR @show_own_spid IS NULL
758 OR @show_system_spids IS NULL
759 OR @show_sleeping_spids IS NULL
760 OR @get_full_inner_text IS NULL
761 OR @get_plans IS NULL
762 OR @get_outer_command IS NULL
763 OR @get_transaction_info IS NULL
764 OR @get_task_info IS NULL
765 OR @get_locks IS NULL
766 OR @get_avg_time IS NULL
767 OR @get_additional_info IS NULL
768 OR @find_block_leaders IS NULL
769 OR @delta_interval IS NULL
770 OR @format_output IS NULL
771 OR @output_column_list IS NULL
772 OR @sort_order IS NULL
773 OR @return_schema IS NULL
774 OR @destination_table IS NULL
775 OR @help IS NULL
776 BEGIN;
777 RAISERROR('Input parameters cannot be NULL', 16, 1);
778 RETURN;
779 END;
780
781 IF @filter_type NOT IN ('session', 'program', 'database', 'login', 'host')
782 BEGIN;
783 RAISERROR('Valid filter types are: session, program, database, login, host', 16, 1);
784 RETURN;
785 END;
786
787 IF @filter_type = 'session' AND @filter LIKE '%[^0123456789]%'
788 BEGIN;
789 RAISERROR('Session filters must be valid integers', 16, 1);
790 RETURN;
791 END;
792
793 IF @not_filter_type NOT IN ('session', 'program', 'database', 'login', 'host')
794 BEGIN;
795 RAISERROR('Valid filter types are: session, program, database, login, host', 16, 1);
796 RETURN;
797 END;
798
799 IF @not_filter_type = 'session' AND @not_filter LIKE '%[^0123456789]%'
800 BEGIN;
801 RAISERROR('Session filters must be valid integers', 16, 1);
802 RETURN;
803 END;
804
805 IF @show_sleeping_spids NOT IN (0, 1, 2)
806 BEGIN;
807 RAISERROR('Valid values for @show_sleeping_spids are: 0, 1, or 2', 16, 1);
808 RETURN;
809 END;
810
811 IF @get_plans NOT IN (0, 1, 2)
812 BEGIN;
813 RAISERROR('Valid values for @get_plans are: 0, 1, or 2', 16, 1);
814 RETURN;
815 END;
816
817 IF @get_task_info NOT IN (0, 1, 2)
818 BEGIN;
819 RAISERROR('Valid values for @get_task_info are: 0, 1, or 2', 16, 1);
820 RETURN;
821 END;
822
823 IF @format_output NOT IN (0, 1, 2)
824 BEGIN;
825 RAISERROR('Valid values for @format_output are: 0, 1, or 2', 16, 1);
826 RETURN;
827 END;
828
829 IF @help = 1
830 BEGIN;
831 DECLARE
832 @header VARCHAR(MAX),
833 @params VARCHAR(MAX),
834 @outputs VARCHAR(MAX);
835
836 SELECT
837 @header =
838 REPLACE
839 (
840 REPLACE
841 (
842 CONVERT
843 (
844 VARCHAR(MAX),
845 SUBSTRING
846 (
847 t.text,
848 CHARINDEX('/' + REPLICATE('*', 93), t.text) + 94,
849 CHARINDEX(REPLICATE('*', 93) + '/', t.text) - (CHARINDEX('/' + REPLICATE('*', 93), t.text) + 94)
850 )
851 ),
852 CHAR(13)+CHAR(10),
853 CHAR(13)
854 ),
855 ' ',
856 ''
857 ),
858 @params =
859 CHAR(13) +
860 REPLACE
861 (
862 REPLACE
863 (
864 CONVERT
865 (
866 VARCHAR(MAX),
867 SUBSTRING
868 (
869 t.text,
870 CHARINDEX('--~', t.text) + 5,
871 CHARINDEX('--~', t.text, CHARINDEX('--~', t.text) + 5) - (CHARINDEX('--~', t.text) + 5)
872 )
873 ),
874 CHAR(13)+CHAR(10),
875 CHAR(13)
876 ),
877 ' ',
878 ''
879 ),
880 @outputs =
881 CHAR(13) +
882 REPLACE
883 (
884 REPLACE
885 (
886 REPLACE
887 (
888 CONVERT
889 (
890 VARCHAR(MAX),
891 SUBSTRING
892 (
893 t.text,
894 CHARINDEX('OUTPUT COLUMNS'+CHAR(13)+CHAR(10)+'--------------', t.text) + 32,
895 CHARINDEX('*/', t.text, CHARINDEX('OUTPUT COLUMNS'+CHAR(13)+CHAR(10)+'--------------', t.text) + 32) - (CHARINDEX('OUTPUT COLUMNS'+CHAR(13)+CHAR(10)+'--------------', t.text) + 32)
896 )
897 ),
898 CHAR(9),
899 CHAR(255)
900 ),
901 CHAR(13)+CHAR(10),
902 CHAR(13)
903 ),
904 ' ',
905 ''
906 ) +
907 CHAR(13)
908 FROM sys.dm_exec_requests AS r
909 CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t
910 WHERE
911 r.session_id = @@SPID;
912
913 WITH
914 a0 AS
915 (SELECT 1 AS n UNION ALL SELECT 1),
916 a1 AS
917 (SELECT 1 AS n FROM a0 AS a, a0 AS b),
918 a2 AS
919 (SELECT 1 AS n FROM a1 AS a, a1 AS b),
920 a3 AS
921 (SELECT 1 AS n FROM a2 AS a, a2 AS b),
922 a4 AS
923 (SELECT 1 AS n FROM a3 AS a, a3 AS b),
924 numbers AS
925 (
926 SELECT TOP(LEN(@header) - 1)
927 ROW_NUMBER() OVER
928 (
929 ORDER BY (SELECT NULL)
930 ) AS number
931 FROM a4
932 ORDER BY
933 number
934 )
935 SELECT
936 RTRIM(LTRIM(
937 SUBSTRING
938 (
939 @header,
940 number + 1,
941 CHARINDEX(CHAR(13), @header, number + 1) - number - 1
942 )
943 )) AS [------header---------------------------------------------------------------------------------------------------------------]
944 FROM numbers
945 WHERE
946 SUBSTRING(@header, number, 1) = CHAR(13);
947
948 WITH
949 a0 AS
950 (SELECT 1 AS n UNION ALL SELECT 1),
951 a1 AS
952 (SELECT 1 AS n FROM a0 AS a, a0 AS b),
953 a2 AS
954 (SELECT 1 AS n FROM a1 AS a, a1 AS b),
955 a3 AS
956 (SELECT 1 AS n FROM a2 AS a, a2 AS b),
957 a4 AS
958 (SELECT 1 AS n FROM a3 AS a, a3 AS b),
959 numbers AS
960 (
961 SELECT TOP(LEN(@params) - 1)
962 ROW_NUMBER() OVER
963 (
964 ORDER BY (SELECT NULL)
965 ) AS number
966 FROM a4
967 ORDER BY
968 number
969 ),
970 tokens AS
971 (
972 SELECT
973 RTRIM(LTRIM(
974 SUBSTRING
975 (
976 @params,
977 number + 1,
978 CHARINDEX(CHAR(13), @params, number + 1) - number - 1
979 )
980 )) AS token,
981 number,
982 CASE
983 WHEN SUBSTRING(@params, number + 1, 1) = CHAR(13) THEN number
984 ELSE COALESCE(NULLIF(CHARINDEX(',' + CHAR(13) + CHAR(13), @params, number), 0), LEN(@params))
985 END AS param_group,
986 ROW_NUMBER() OVER
987 (
988 PARTITION BY
989 CHARINDEX(',' + CHAR(13) + CHAR(13), @params, number),
990 SUBSTRING(@params, number+1, 1)
991 ORDER BY
992 number
993 ) AS group_order
994 FROM numbers
995 WHERE
996 SUBSTRING(@params, number, 1) = CHAR(13)
997 ),
998 parsed_tokens AS
999 (
1000 SELECT
1001 MIN
1002 (
1003 CASE
1004 WHEN token LIKE '@%' THEN token
1005 ELSE NULL
1006 END
1007 ) AS parameter,
1008 MIN
1009 (
1010 CASE
1011 WHEN token LIKE '--%' THEN RIGHT(token, LEN(token) - 2)
1012 ELSE NULL
1013 END
1014 ) AS description,
1015 param_group,
1016 group_order
1017 FROM tokens
1018 WHERE
1019 NOT
1020 (
1021 token = ''
1022 AND group_order > 1
1023 )
1024 GROUP BY
1025 param_group,
1026 group_order
1027 )
1028 SELECT
1029 CASE
1030 WHEN description IS NULL AND parameter IS NULL THEN '-------------------------------------------------------------------------'
1031 WHEN param_group = MAX(param_group) OVER() THEN parameter
1032 ELSE COALESCE(LEFT(parameter, LEN(parameter) - 1), '')
1033 END AS [------parameter----------------------------------------------------------],
1034 CASE
1035 WHEN description IS NULL AND parameter IS NULL THEN '----------------------------------------------------------------------------------------------------------------------'
1036 ELSE COALESCE(description, '')
1037 END AS [------description-----------------------------------------------------------------------------------------------------]
1038 FROM parsed_tokens
1039 ORDER BY
1040 param_group,
1041 group_order;
1042
1043 WITH
1044 a0 AS
1045 (SELECT 1 AS n UNION ALL SELECT 1),
1046 a1 AS
1047 (SELECT 1 AS n FROM a0 AS a, a0 AS b),
1048 a2 AS
1049 (SELECT 1 AS n FROM a1 AS a, a1 AS b),
1050 a3 AS
1051 (SELECT 1 AS n FROM a2 AS a, a2 AS b),
1052 a4 AS
1053 (SELECT 1 AS n FROM a3 AS a, a3 AS b),
1054 numbers AS
1055 (
1056 SELECT TOP(LEN(@outputs) - 1)
1057 ROW_NUMBER() OVER
1058 (
1059 ORDER BY (SELECT NULL)
1060 ) AS number
1061 FROM a4
1062 ORDER BY
1063 number
1064 ),
1065 tokens AS
1066 (
1067 SELECT
1068 RTRIM(LTRIM(
1069 SUBSTRING
1070 (
1071 @outputs,
1072 number + 1,
1073 CASE
1074 WHEN
1075 COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs)) <
1076 COALESCE(NULLIF(CHARINDEX(CHAR(13) + CHAR(255) COLLATE Latin1_General_Bin2, @outputs, number + 1), 0), LEN(@outputs))
1077 THEN COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs)) - number - 1
1078 ELSE
1079 COALESCE(NULLIF(CHARINDEX(CHAR(13) + CHAR(255) COLLATE Latin1_General_Bin2, @outputs, number + 1), 0), LEN(@outputs)) - number - 1
1080 END
1081 )
1082 )) AS token,
1083 number,
1084 COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs)) AS output_group,
1085 ROW_NUMBER() OVER
1086 (
1087 PARTITION BY
1088 COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs))
1089 ORDER BY
1090 number
1091 ) AS output_group_order
1092 FROM numbers
1093 WHERE
1094 SUBSTRING(@outputs, number, 10) = CHAR(13) + 'Formatted'
1095 OR SUBSTRING(@outputs, number, 2) = CHAR(13) + CHAR(255) COLLATE Latin1_General_Bin2
1096 ),
1097 output_tokens AS
1098 (
1099 SELECT
1100 *,
1101 CASE output_group_order
1102 WHEN 2 THEN MAX(CASE output_group_order WHEN 1 THEN token ELSE NULL END) OVER (PARTITION BY output_group)
1103 ELSE ''
1104 END COLLATE Latin1_General_Bin2 AS column_info
1105 FROM tokens
1106 )
1107 SELECT
1108 CASE output_group_order
1109 WHEN 1 THEN '-----------------------------------'
1110 WHEN 2 THEN
1111 CASE
1112 WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN
1113 SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+1, CHARINDEX(']', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+2) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info))
1114 ELSE
1115 SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+2, CHARINDEX(']', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+2) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)-1)
1116 END
1117 ELSE ''
1118 END AS formatted_column_name,
1119 CASE output_group_order
1120 WHEN 1 THEN '-----------------------------------'
1121 WHEN 2 THEN
1122 CASE
1123 WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN
1124 SUBSTRING(column_info, CHARINDEX(']', column_info)+2, LEN(column_info))
1125 ELSE
1126 SUBSTRING(column_info, CHARINDEX(']', column_info)+2, CHARINDEX('Non-Formatted:', column_info, CHARINDEX(']', column_info)+2) - CHARINDEX(']', column_info)-3)
1127 END
1128 ELSE ''
1129 END AS formatted_column_type,
1130 CASE output_group_order
1131 WHEN 1 THEN '---------------------------------------'
1132 WHEN 2 THEN
1133 CASE
1134 WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN ''
1135 ELSE
1136 CASE
1137 WHEN SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, 1) = '<' THEN
1138 SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, CHARINDEX('>', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info)))
1139 ELSE
1140 SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, CHARINDEX(']', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info)))
1141 END
1142 END
1143 ELSE ''
1144 END AS unformatted_column_name,
1145 CASE output_group_order
1146 WHEN 1 THEN '---------------------------------------'
1147 WHEN 2 THEN
1148 CASE
1149 WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN ''
1150 ELSE
1151 CASE
1152 WHEN SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, 1) = '<' THEN ''
1153 ELSE
1154 SUBSTRING(column_info, CHARINDEX(']', column_info, CHARINDEX('Non-Formatted:', column_info))+2, CHARINDEX('Non-Formatted:', column_info, CHARINDEX(']', column_info)+2) - CHARINDEX(']', column_info)-3)
1155 END
1156 END
1157 ELSE ''
1158 END AS unformatted_column_type,
1159 CASE output_group_order
1160 WHEN 1 THEN '----------------------------------------------------------------------------------------------------------------------'
1161 ELSE REPLACE(token, CHAR(255) COLLATE Latin1_General_Bin2, '')
1162 END AS [------description-----------------------------------------------------------------------------------------------------]
1163 FROM output_tokens
1164 WHERE
1165 NOT
1166 (
1167 output_group_order = 1
1168 AND output_group = LEN(@outputs)
1169 )
1170 ORDER BY
1171 output_group,
1172 CASE output_group_order
1173 WHEN 1 THEN 99
1174 ELSE output_group_order
1175 END;
1176
1177 RETURN;
1178 END;
1179
1180 WITH
1181 a0 AS
1182 (SELECT 1 AS n UNION ALL SELECT 1),
1183 a1 AS
1184 (SELECT 1 AS n FROM a0 AS a, a0 AS b),
1185 a2 AS
1186 (SELECT 1 AS n FROM a1 AS a, a1 AS b),
1187 a3 AS
1188 (SELECT 1 AS n FROM a2 AS a, a2 AS b),
1189 a4 AS
1190 (SELECT 1 AS n FROM a3 AS a, a3 AS b),
1191 numbers AS
1192 (
1193 SELECT TOP(LEN(@output_column_list))
1194 ROW_NUMBER() OVER
1195 (
1196 ORDER BY (SELECT NULL)
1197 ) AS number
1198 FROM a4
1199 ORDER BY
1200 number
1201 ),
1202 tokens AS
1203 (
1204 SELECT
1205 '|[' +
1206 SUBSTRING
1207 (
1208 @output_column_list,
1209 number + 1,
1210 CHARINDEX(']', @output_column_list, number) - number - 1
1211 ) + '|]' AS token,
1212 number
1213 FROM numbers
1214 WHERE
1215 SUBSTRING(@output_column_list, number, 1) = '['
1216 ),
1217 ordered_columns AS
1218 (
1219 SELECT
1220 x.column_name,
1221 ROW_NUMBER() OVER
1222 (
1223 PARTITION BY
1224 x.column_name
1225 ORDER BY
1226 tokens.number,
1227 x.default_order
1228 ) AS r,
1229 ROW_NUMBER() OVER
1230 (
1231 ORDER BY
1232 tokens.number,
1233 x.default_order
1234 ) AS s
1235 FROM tokens
1236 JOIN
1237 (
1238 SELECT '[session_id]' AS column_name, 1 AS default_order
1239 UNION ALL
1240 SELECT '[dd hh:mm:ss.mss]', 2
1241 WHERE
1242 @format_output IN (1, 2)
1243 UNION ALL
1244 SELECT '[dd hh:mm:ss.mss (avg)]', 3
1245 WHERE
1246 @format_output IN (1, 2)
1247 AND @get_avg_time = 1
1248 UNION ALL
1249 SELECT '[avg_elapsed_time]', 4
1250 WHERE
1251 @format_output = 0
1252 AND @get_avg_time = 1
1253 UNION ALL
1254 SELECT '[physical_io]', 5
1255 WHERE
1256 @get_task_info = 2
1257 UNION ALL
1258 SELECT '[reads]', 6
1259 UNION ALL
1260 SELECT '[physical_reads]', 7
1261 UNION ALL
1262 SELECT '[writes]', 8
1263 UNION ALL
1264 SELECT '[tempdb_allocations]', 9
1265 UNION ALL
1266 SELECT '[tempdb_current]', 10
1267 UNION ALL
1268 SELECT '[CPU]', 11
1269 UNION ALL
1270 SELECT '[context_switches]', 12
1271 WHERE
1272 @get_task_info = 2
1273 UNION ALL
1274 SELECT '[used_memory]', 13
1275 UNION ALL
1276 SELECT '[physical_io_delta]', 14
1277 WHERE
1278 @delta_interval > 0
1279 AND @get_task_info = 2
1280 UNION ALL
1281 SELECT '[reads_delta]', 15
1282 WHERE
1283 @delta_interval > 0
1284 UNION ALL
1285 SELECT '[physical_reads_delta]', 16
1286 WHERE
1287 @delta_interval > 0
1288 UNION ALL
1289 SELECT '[writes_delta]', 17
1290 WHERE
1291 @delta_interval > 0
1292 UNION ALL
1293 SELECT '[tempdb_allocations_delta]', 18
1294 WHERE
1295 @delta_interval > 0
1296 UNION ALL
1297 SELECT '[tempdb_current_delta]', 19
1298 WHERE
1299 @delta_interval > 0
1300 UNION ALL
1301 SELECT '[CPU_delta]', 20
1302 WHERE
1303 @delta_interval > 0
1304 UNION ALL
1305 SELECT '[context_switches_delta]', 21
1306 WHERE
1307 @delta_interval > 0
1308 AND @get_task_info = 2
1309 UNION ALL
1310 SELECT '[used_memory_delta]', 22
1311 WHERE
1312 @delta_interval > 0
1313 UNION ALL
1314 SELECT '[tasks]', 23
1315 WHERE
1316 @get_task_info = 2
1317 UNION ALL
1318 SELECT '[status]', 24
1319 UNION ALL
1320 SELECT '[wait_info]', 25
1321 WHERE
1322 @get_task_info > 0
1323 OR @find_block_leaders = 1
1324 UNION ALL
1325 SELECT '[locks]', 26
1326 WHERE
1327 @get_locks = 1
1328 UNION ALL
1329 SELECT '[tran_start_time]', 27
1330 WHERE
1331 @get_transaction_info = 1
1332 UNION ALL
1333 SELECT '[tran_log_writes]', 28
1334 WHERE
1335 @get_transaction_info = 1
1336 UNION ALL
1337 SELECT '[open_tran_count]', 29
1338 UNION ALL
1339 SELECT '[sql_command]', 30
1340 WHERE
1341 @get_outer_command = 1
1342 UNION ALL
1343 SELECT '[sql_text]', 31
1344 UNION ALL
1345 SELECT '[query_plan]', 32
1346 WHERE
1347 @get_plans >= 1
1348 UNION ALL
1349 SELECT '[blocking_session_id]', 33
1350 WHERE
1351 @get_task_info > 0
1352 OR @find_block_leaders = 1
1353 UNION ALL
1354 SELECT '[blocked_session_count]', 34
1355 WHERE
1356 @find_block_leaders = 1
1357 UNION ALL
1358 SELECT '[percent_complete]', 35
1359 UNION ALL
1360 SELECT '[host_name]', 36
1361 UNION ALL
1362 SELECT '[login_name]', 37
1363 UNION ALL
1364 SELECT '[database_name]', 38
1365 UNION ALL
1366 SELECT '[program_name]', 39
1367 UNION ALL
1368 SELECT '[additional_info]', 40
1369 WHERE
1370 @get_additional_info = 1
1371 UNION ALL
1372 SELECT '[start_time]', 41
1373 UNION ALL
1374 SELECT '[login_time]', 42
1375 UNION ALL
1376 SELECT '[request_id]', 43
1377 UNION ALL
1378 SELECT '[collection_time]', 44
1379 ) AS x ON
1380 x.column_name LIKE token ESCAPE '|'
1381 )
1382 SELECT
1383 @output_column_list =
1384 STUFF
1385 (
1386 (
1387 SELECT
1388 ',' + column_name as [text()]
1389 FROM ordered_columns
1390 WHERE
1391 r = 1
1392 ORDER BY
1393 s
1394 FOR XML
1395 PATH('')
1396 ),
1397 1,
1398 1,
1399 ''
1400 );
1401
1402 IF COALESCE(RTRIM(@output_column_list), '') = ''
1403 BEGIN;
1404 RAISERROR('No valid column matches found in @output_column_list or no columns remain due to selected options.', 16, 1);
1405 RETURN;
1406 END;
1407
1408 IF @destination_table <> ''
1409 BEGIN;
1410 SET @destination_table =
1411 --database
1412 COALESCE(QUOTENAME(PARSENAME(@destination_table, 3)) + '.', '') +
1413 --schema
1414 COALESCE(QUOTENAME(PARSENAME(@destination_table, 2)) + '.', '') +
1415 --table
1416 COALESCE(QUOTENAME(PARSENAME(@destination_table, 1)), '');
1417
1418 IF COALESCE(RTRIM(@destination_table), '') = ''
1419 BEGIN;
1420 RAISERROR('Destination table not properly formatted.', 16, 1);
1421 RETURN;
1422 END;
1423 END;
1424
1425 WITH
1426 a0 AS
1427 (SELECT 1 AS n UNION ALL SELECT 1),
1428 a1 AS
1429 (SELECT 1 AS n FROM a0 AS a, a0 AS b),
1430 a2 AS
1431 (SELECT 1 AS n FROM a1 AS a, a1 AS b),
1432 a3 AS
1433 (SELECT 1 AS n FROM a2 AS a, a2 AS b),
1434 a4 AS
1435 (SELECT 1 AS n FROM a3 AS a, a3 AS b),
1436 numbers AS
1437 (
1438 SELECT TOP(LEN(@sort_order))
1439 ROW_NUMBER() OVER
1440 (
1441 ORDER BY (SELECT NULL)
1442 ) AS number
1443 FROM a4
1444 ORDER BY
1445 number
1446 ),
1447 tokens AS
1448 (
1449 SELECT
1450 '|[' +
1451 SUBSTRING
1452 (
1453 @sort_order,
1454 number + 1,
1455 CHARINDEX(']', @sort_order, number) - number - 1
1456 ) + '|]' AS token,
1457 SUBSTRING
1458 (
1459 @sort_order,
1460 CHARINDEX(']', @sort_order, number) + 1,
1461 COALESCE(NULLIF(CHARINDEX('[', @sort_order, CHARINDEX(']', @sort_order, number)), 0), LEN(@sort_order)) - CHARINDEX(']', @sort_order, number)
1462 ) AS next_chunk,
1463 number
1464 FROM numbers
1465 WHERE
1466 SUBSTRING(@sort_order, number, 1) = '['
1467 ),
1468 ordered_columns AS
1469 (
1470 SELECT
1471 x.column_name +
1472 CASE
1473 WHEN tokens.next_chunk LIKE '%asc%' THEN ' ASC'
1474 WHEN tokens.next_chunk LIKE '%desc%' THEN ' DESC'
1475 ELSE ''
1476 END AS column_name,
1477 ROW_NUMBER() OVER
1478 (
1479 PARTITION BY
1480 x.column_name
1481 ORDER BY
1482 tokens.number
1483 ) AS r,
1484 tokens.number
1485 FROM tokens
1486 JOIN
1487 (
1488 SELECT '[session_id]' AS column_name
1489 UNION ALL
1490 SELECT '[physical_io]'
1491 UNION ALL
1492 SELECT '[reads]'
1493 UNION ALL
1494 SELECT '[physical_reads]'
1495 UNION ALL
1496 SELECT '[writes]'
1497 UNION ALL
1498 SELECT '[tempdb_allocations]'
1499 UNION ALL
1500 SELECT '[tempdb_current]'
1501 UNION ALL
1502 SELECT '[CPU]'
1503 UNION ALL
1504 SELECT '[context_switches]'
1505 UNION ALL
1506 SELECT '[used_memory]'
1507 UNION ALL
1508 SELECT '[physical_io_delta]'
1509 UNION ALL
1510 SELECT '[reads_delta]'
1511 UNION ALL
1512 SELECT '[physical_reads_delta]'
1513 UNION ALL
1514 SELECT '[writes_delta]'
1515 UNION ALL
1516 SELECT '[tempdb_allocations_delta]'
1517 UNION ALL
1518 SELECT '[tempdb_current_delta]'
1519 UNION ALL
1520 SELECT '[CPU_delta]'
1521 UNION ALL
1522 SELECT '[context_switches_delta]'
1523 UNION ALL
1524 SELECT '[used_memory_delta]'
1525 UNION ALL
1526 SELECT '[tasks]'
1527 UNION ALL
1528 SELECT '[tran_start_time]'
1529 UNION ALL
1530 SELECT '[open_tran_count]'
1531 UNION ALL
1532 SELECT '[blocking_session_id]'
1533 UNION ALL
1534 SELECT '[blocked_session_count]'
1535 UNION ALL
1536 SELECT '[percent_complete]'
1537 UNION ALL
1538 SELECT '[host_name]'
1539 UNION ALL
1540 SELECT '[login_name]'
1541 UNION ALL
1542 SELECT '[database_name]'
1543 UNION ALL
1544 SELECT '[start_time]'
1545 UNION ALL
1546 SELECT '[login_time]'
1547 ) AS x ON
1548 x.column_name LIKE token ESCAPE '|'
1549 )
1550 SELECT
1551 @sort_order = COALESCE(z.sort_order, '')
1552 FROM
1553 (
1554 SELECT
1555 STUFF
1556 (
1557 (
1558 SELECT
1559 ',' + column_name as [text()]
1560 FROM ordered_columns
1561 WHERE
1562 r = 1
1563 ORDER BY
1564 number
1565 FOR XML
1566 PATH('')
1567 ),
1568 1,
1569 1,
1570 ''
1571 ) AS sort_order
1572 ) AS z;
1573
1574 CREATE TABLE #sessions
1575 (
1576 recursion SMALLINT NOT NULL,
1577 session_id SMALLINT NOT NULL,
1578 request_id INT NOT NULL,
1579 session_number INT NOT NULL,
1580 elapsed_time INT NOT NULL,
1581 avg_elapsed_time INT NULL,
1582 physical_io BIGINT NULL,
1583 reads BIGINT NULL,
1584 physical_reads BIGINT NULL,
1585 writes BIGINT NULL,
1586 tempdb_allocations BIGINT NULL,
1587 tempdb_current BIGINT NULL,
1588 CPU INT NULL,
1589 thread_CPU_snapshot BIGINT NULL,
1590 context_switches BIGINT NULL,
1591 used_memory BIGINT NOT NULL,
1592 tasks SMALLINT NULL,
1593 status VARCHAR(30) NOT NULL,
1594 wait_info NVARCHAR(4000) NULL,
1595 locks XML NULL,
1596 transaction_id BIGINT NULL,
1597 tran_start_time DATETIME NULL,
1598 tran_log_writes NVARCHAR(4000) NULL,
1599 open_tran_count SMALLINT NULL,
1600 sql_command XML NULL,
1601 sql_handle VARBINARY(64) NULL,
1602 statement_start_offset INT NULL,
1603 statement_end_offset INT NULL,
1604 sql_text XML NULL,
1605 plan_handle VARBINARY(64) NULL,
1606 query_plan XML NULL,
1607 blocking_session_id SMALLINT NULL,
1608 blocked_session_count SMALLINT NULL,
1609 percent_complete REAL NULL,
1610 host_name sysname NULL,
1611 login_name sysname NOT NULL,
1612 database_name sysname NULL,
1613 program_name sysname NULL,
1614 additional_info XML NULL,
1615 start_time DATETIME NOT NULL,
1616 login_time DATETIME NULL,
1617 last_request_start_time DATETIME NULL,
1618 PRIMARY KEY CLUSTERED (session_id, request_id, recursion) WITH (IGNORE_DUP_KEY = ON),
1619 UNIQUE NONCLUSTERED (transaction_id, session_id, request_id, recursion) WITH (IGNORE_DUP_KEY = ON)
1620 );
1621
1622 IF @return_schema = 0
1623 BEGIN;
1624 --Disable unnecessary autostats on the table
1625 CREATE STATISTICS s_session_id ON #sessions (session_id)
1626 WITH SAMPLE 0 ROWS, NORECOMPUTE;
1627 CREATE STATISTICS s_request_id ON #sessions (request_id)
1628 WITH SAMPLE 0 ROWS, NORECOMPUTE;
1629 CREATE STATISTICS s_transaction_id ON #sessions (transaction_id)
1630 WITH SAMPLE 0 ROWS, NORECOMPUTE;
1631 CREATE STATISTICS s_session_number ON #sessions (session_number)
1632 WITH SAMPLE 0 ROWS, NORECOMPUTE;
1633 CREATE STATISTICS s_status ON #sessions (status)
1634 WITH SAMPLE 0 ROWS, NORECOMPUTE;
1635 CREATE STATISTICS s_start_time ON #sessions (start_time)
1636 WITH SAMPLE 0 ROWS, NORECOMPUTE;
1637 CREATE STATISTICS s_last_request_start_time ON #sessions (last_request_start_time)
1638 WITH SAMPLE 0 ROWS, NORECOMPUTE;
1639 CREATE STATISTICS s_recursion ON #sessions (recursion)
1640 WITH SAMPLE 0 ROWS, NORECOMPUTE;
1641
1642 DECLARE @recursion SMALLINT;
1643 SET @recursion =
1644 CASE @delta_interval
1645 WHEN 0 THEN 1
1646 ELSE -1
1647 END;
1648
1649 DECLARE @first_collection_ms_ticks BIGINT;
1650 DECLARE @last_collection_start DATETIME;
1651
1652 --Used for the delta pull
1653 REDO:;
1654
1655 IF
1656 @get_locks = 1
1657 AND @recursion = 1
1658 AND @output_column_list LIKE '%|[locks|]%' ESCAPE '|'
1659 BEGIN;
1660 SELECT
1661 y.resource_type,
1662 y.database_name,
1663 y.object_id,
1664 y.file_id,
1665 y.page_type,
1666 y.hobt_id,
1667 y.allocation_unit_id,
1668 y.index_id,
1669 y.schema_id,
1670 y.principal_id,
1671 y.request_mode,
1672 y.request_status,
1673 y.session_id,
1674 y.resource_description,
1675 y.request_count,
1676 s.request_id,
1677 s.start_time,
1678 CONVERT(sysname, NULL) AS object_name,
1679 CONVERT(sysname, NULL) AS index_name,
1680 CONVERT(sysname, NULL) AS schema_name,
1681 CONVERT(sysname, NULL) AS principal_name,
1682 CONVERT(NVARCHAR(2048), NULL) AS query_error
1683 INTO #locks
1684 FROM
1685 (
1686 SELECT
1687 sp.spid AS session_id,
1688 CASE sp.status
1689 WHEN 'sleeping' THEN CONVERT(INT, 0)
1690 ELSE sp.request_id
1691 END AS request_id,
1692 CASE sp.status
1693 WHEN 'sleeping' THEN sp.last_batch
1694 ELSE COALESCE(req.start_time, sp.last_batch)
1695 END AS start_time,
1696 sp.dbid
1697 FROM sys.sysprocesses AS sp
1698 OUTER APPLY
1699 (
1700 SELECT TOP(1)
1701 CASE
1702 WHEN
1703 (
1704 sp.hostprocess > ''
1705 OR r.total_elapsed_time < 0
1706 ) THEN
1707 r.start_time
1708 ELSE
1709 DATEADD
1710 (
1711 ms,
1712 1000 * (DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())) / 500) - DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())),
1713 DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())
1714 )
1715 END AS start_time
1716 FROM sys.dm_exec_requests AS r
1717 WHERE
1718 r.session_id = sp.spid
1719 AND r.request_id = sp.request_id
1720 ) AS req
1721 WHERE
1722 --Process inclusive filter
1723 1 =
1724 CASE
1725 WHEN @filter <> '' THEN
1726 CASE @filter_type
1727 WHEN 'session' THEN
1728 CASE
1729 WHEN
1730 CONVERT(SMALLINT, @filter) = 0
1731 OR sp.spid = CONVERT(SMALLINT, @filter)
1732 THEN 1
1733 ELSE 0
1734 END
1735 WHEN 'program' THEN
1736 CASE
1737 WHEN sp.program_name LIKE @filter THEN 1
1738 ELSE 0
1739 END
1740 WHEN 'login' THEN
1741 CASE
1742 WHEN sp.loginame LIKE @filter THEN 1
1743 ELSE 0
1744 END
1745 WHEN 'host' THEN
1746 CASE
1747 WHEN sp.hostname LIKE @filter THEN 1
1748 ELSE 0
1749 END
1750 WHEN 'database' THEN
1751 CASE
1752 WHEN DB_NAME(sp.dbid) LIKE @filter THEN 1
1753 ELSE 0
1754 END
1755 ELSE 0
1756 END
1757 ELSE 1
1758 END
1759 --Process exclusive filter
1760 AND 0 =
1761 CASE
1762 WHEN @not_filter <> '' THEN
1763 CASE @not_filter_type
1764 WHEN 'session' THEN
1765 CASE
1766 WHEN sp.spid = CONVERT(SMALLINT, @not_filter) THEN 1
1767 ELSE 0
1768 END
1769 WHEN 'program' THEN
1770 CASE
1771 WHEN sp.program_name LIKE @not_filter THEN 1
1772 ELSE 0
1773 END
1774 WHEN 'login' THEN
1775 CASE
1776 WHEN sp.loginame LIKE @not_filter THEN 1
1777 ELSE 0
1778 END
1779 WHEN 'host' THEN
1780 CASE
1781 WHEN sp.hostname LIKE @not_filter THEN 1
1782 ELSE 0
1783 END
1784 WHEN 'database' THEN
1785 CASE
1786 WHEN DB_NAME(sp.dbid) LIKE @not_filter THEN 1
1787 ELSE 0
1788 END
1789 ELSE 0
1790 END
1791 ELSE 0
1792 END
1793 AND
1794 (
1795 @show_own_spid = 1
1796 OR sp.spid <> @@SPID
1797 )
1798 AND
1799 (
1800 @show_system_spids = 1
1801 OR sp.hostprocess > ''
1802 )
1803 AND sp.ecid = 0
1804 ) AS s
1805 INNER HASH JOIN
1806 (
1807 SELECT
1808 x.resource_type,
1809 x.database_name,
1810 x.object_id,
1811 x.file_id,
1812 CASE
1813 WHEN x.page_no = 1 OR x.page_no % 8088 = 0 THEN 'PFS'
1814 WHEN x.page_no = 2 OR x.page_no % 511232 = 0 THEN 'GAM'
1815 WHEN x.page_no = 3 OR x.page_no % 511233 = 0 THEN 'SGAM'
1816 WHEN x.page_no = 6 OR x.page_no % 511238 = 0 THEN 'DCM'
1817 WHEN x.page_no = 7 OR x.page_no % 511239 = 0 THEN 'BCM'
1818 WHEN x.page_no IS NOT NULL THEN '*'
1819 ELSE NULL
1820 END AS page_type,
1821 x.hobt_id,
1822 x.allocation_unit_id,
1823 x.index_id,
1824 x.schema_id,
1825 x.principal_id,
1826 x.request_mode,
1827 x.request_status,
1828 x.session_id,
1829 x.request_id,
1830 CASE
1831 WHEN COALESCE(x.object_id, x.file_id, x.hobt_id, x.allocation_unit_id, x.index_id, x.schema_id, x.principal_id) IS NULL THEN NULLIF(resource_description, '')
1832 ELSE NULL
1833 END AS resource_description,
1834 COUNT(*) AS request_count
1835 FROM
1836 (
1837 SELECT
1838 tl.resource_type +
1839 CASE
1840 WHEN tl.resource_subtype = '' THEN ''
1841 ELSE '.' + tl.resource_subtype
1842 END AS resource_type,
1843 COALESCE(DB_NAME(tl.resource_database_id), N'(null)') AS database_name,
1844 CONVERT
1845 (
1846 INT,
1847 CASE
1848 WHEN tl.resource_type = 'OBJECT' THEN tl.resource_associated_entity_id
1849 WHEN tl.resource_description LIKE '%object_id = %' THEN
1850 (
1851 SUBSTRING
1852 (
1853 tl.resource_description,
1854 (CHARINDEX('object_id = ', tl.resource_description) + 12),
1855 COALESCE
1856 (
1857 NULLIF
1858 (
1859 CHARINDEX(',', tl.resource_description, CHARINDEX('object_id = ', tl.resource_description) + 12),
1860 0
1861 ),
1862 DATALENGTH(tl.resource_description)+1
1863 ) - (CHARINDEX('object_id = ', tl.resource_description) + 12)
1864 )
1865 )
1866 ELSE NULL
1867 END
1868 ) AS object_id,
1869 CONVERT
1870 (
1871 INT,
1872 CASE
1873 WHEN tl.resource_type = 'FILE' THEN CONVERT(INT, tl.resource_description)
1874 WHEN tl.resource_type IN ('PAGE', 'EXTENT', 'RID') THEN LEFT(tl.resource_description, CHARINDEX(':', tl.resource_description)-1)
1875 ELSE NULL
1876 END
1877 ) AS file_id,
1878 CONVERT
1879 (
1880 INT,
1881 CASE
1882 WHEN tl.resource_type IN ('PAGE', 'EXTENT', 'RID') THEN
1883 SUBSTRING
1884 (
1885 tl.resource_description,
1886 CHARINDEX(':', tl.resource_description) + 1,
1887 COALESCE
1888 (
1889 NULLIF
1890 (
1891 CHARINDEX(':', tl.resource_description, CHARINDEX(':', tl.resource_description) + 1),
1892 0
1893 ),
1894 DATALENGTH(tl.resource_description)+1
1895 ) - (CHARINDEX(':', tl.resource_description) + 1)
1896 )
1897 ELSE NULL
1898 END
1899 ) AS page_no,
1900 CASE
1901 WHEN tl.resource_type IN ('PAGE', 'KEY', 'RID', 'HOBT') THEN tl.resource_associated_entity_id
1902 ELSE NULL
1903 END AS hobt_id,
1904 CASE
1905 WHEN tl.resource_type = 'ALLOCATION_UNIT' THEN tl.resource_associated_entity_id
1906 ELSE NULL
1907 END AS allocation_unit_id,
1908 CONVERT
1909 (
1910 INT,
1911 CASE
1912 WHEN
1913 /*TODO: Deal with server principals*/
1914 tl.resource_subtype <> 'SERVER_PRINCIPAL'
1915 AND tl.resource_description LIKE '%index_id or stats_id = %' THEN
1916 (
1917 SUBSTRING
1918 (
1919 tl.resource_description,
1920 (CHARINDEX('index_id or stats_id = ', tl.resource_description) + 23),
1921 COALESCE
1922 (
1923 NULLIF
1924 (
1925 CHARINDEX(',', tl.resource_description, CHARINDEX('index_id or stats_id = ', tl.resource_description) + 23),
1926 0
1927 ),
1928 DATALENGTH(tl.resource_description)+1
1929 ) - (CHARINDEX('index_id or stats_id = ', tl.resource_description) + 23)
1930 )
1931 )
1932 ELSE NULL
1933 END
1934 ) AS index_id,
1935 CONVERT
1936 (
1937 INT,
1938 CASE
1939 WHEN tl.resource_description LIKE '%schema_id = %' THEN
1940 (
1941 SUBSTRING
1942 (
1943 tl.resource_description,
1944 (CHARINDEX('schema_id = ', tl.resource_description) + 12),
1945 COALESCE
1946 (
1947 NULLIF
1948 (
1949 CHARINDEX(',', tl.resource_description, CHARINDEX('schema_id = ', tl.resource_description) + 12),
1950 0
1951 ),
1952 DATALENGTH(tl.resource_description)+1
1953 ) - (CHARINDEX('schema_id = ', tl.resource_description) + 12)
1954 )
1955 )
1956 ELSE NULL
1957 END
1958 ) AS schema_id,
1959 CONVERT
1960 (
1961 INT,
1962 CASE
1963 WHEN tl.resource_description LIKE '%principal_id = %' THEN
1964 (
1965 SUBSTRING
1966 (
1967 tl.resource_description,
1968 (CHARINDEX('principal_id = ', tl.resource_description) + 15),
1969 COALESCE
1970 (
1971 NULLIF
1972 (
1973 CHARINDEX(',', tl.resource_description, CHARINDEX('principal_id = ', tl.resource_description) + 15),
1974 0
1975 ),
1976 DATALENGTH(tl.resource_description)+1
1977 ) - (CHARINDEX('principal_id = ', tl.resource_description) + 15)
1978 )
1979 )
1980 ELSE NULL
1981 END
1982 ) AS principal_id,
1983 tl.request_mode,
1984 tl.request_status,
1985 tl.request_session_id AS session_id,
1986 tl.request_request_id AS request_id,
1987
1988 /*TODO: Applocks, other resource_descriptions*/
1989 RTRIM(tl.resource_description) AS resource_description,
1990 tl.resource_associated_entity_id
1991 /*********************************************/
1992 FROM
1993 (
1994 SELECT
1995 request_session_id,
1996 CONVERT(VARCHAR(120), resource_type) COLLATE Latin1_General_Bin2 AS resource_type,
1997 CONVERT(VARCHAR(120), resource_subtype) COLLATE Latin1_General_Bin2 AS resource_subtype,
1998 resource_database_id,
1999 CONVERT(VARCHAR(512), resource_description) COLLATE Latin1_General_Bin2 AS resource_description,
2000 resource_associated_entity_id,
2001 CONVERT(VARCHAR(120), request_mode) COLLATE Latin1_General_Bin2 AS request_mode,
2002 CONVERT(VARCHAR(120), request_status) COLLATE Latin1_General_Bin2 AS request_status,
2003 request_request_id
2004 FROM sys.dm_tran_locks
2005 ) AS tl
2006 ) AS x
2007 GROUP BY
2008 x.resource_type,
2009 x.database_name,
2010 x.object_id,
2011 x.file_id,
2012 CASE
2013 WHEN x.page_no = 1 OR x.page_no % 8088 = 0 THEN 'PFS'
2014 WHEN x.page_no = 2 OR x.page_no % 511232 = 0 THEN 'GAM'
2015 WHEN x.page_no = 3 OR x.page_no % 511233 = 0 THEN 'SGAM'
2016 WHEN x.page_no = 6 OR x.page_no % 511238 = 0 THEN 'DCM'
2017 WHEN x.page_no = 7 OR x.page_no % 511239 = 0 THEN 'BCM'
2018 WHEN x.page_no IS NOT NULL THEN '*'
2019 ELSE NULL
2020 END,
2021 x.hobt_id,
2022 x.allocation_unit_id,
2023 x.index_id,
2024 x.schema_id,
2025 x.principal_id,
2026 x.request_mode,
2027 x.request_status,
2028 x.session_id,
2029 x.request_id,
2030 CASE
2031 WHEN COALESCE(x.object_id, x.file_id, x.hobt_id, x.allocation_unit_id, x.index_id, x.schema_id, x.principal_id) IS NULL THEN NULLIF(resource_description, '')
2032 ELSE NULL
2033 END
2034 ) AS y ON
2035 y.session_id = s.session_id
2036 AND y.request_id = s.request_id
2037 OPTION (HASH GROUP);
2038
2039 --Disable unnecessary autostats on the table
2040 CREATE STATISTICS s_database_name ON #locks (database_name)
2041 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2042 CREATE STATISTICS s_object_id ON #locks (object_id)
2043 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2044 CREATE STATISTICS s_hobt_id ON #locks (hobt_id)
2045 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2046 CREATE STATISTICS s_allocation_unit_id ON #locks (allocation_unit_id)
2047 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2048 CREATE STATISTICS s_index_id ON #locks (index_id)
2049 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2050 CREATE STATISTICS s_schema_id ON #locks (schema_id)
2051 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2052 CREATE STATISTICS s_principal_id ON #locks (principal_id)
2053 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2054 CREATE STATISTICS s_request_id ON #locks (request_id)
2055 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2056 CREATE STATISTICS s_start_time ON #locks (start_time)
2057 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2058 CREATE STATISTICS s_resource_type ON #locks (resource_type)
2059 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2060 CREATE STATISTICS s_object_name ON #locks (object_name)
2061 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2062 CREATE STATISTICS s_schema_name ON #locks (schema_name)
2063 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2064 CREATE STATISTICS s_page_type ON #locks (page_type)
2065 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2066 CREATE STATISTICS s_request_mode ON #locks (request_mode)
2067 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2068 CREATE STATISTICS s_request_status ON #locks (request_status)
2069 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2070 CREATE STATISTICS s_resource_description ON #locks (resource_description)
2071 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2072 CREATE STATISTICS s_index_name ON #locks (index_name)
2073 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2074 CREATE STATISTICS s_principal_name ON #locks (principal_name)
2075 WITH SAMPLE 0 ROWS, NORECOMPUTE;
2076 END;
2077
2078 DECLARE
2079 @sql VARCHAR(MAX),
2080 @sql_n NVARCHAR(MAX);
2081
2082 SET @sql =
2083 CONVERT(VARCHAR(MAX), '') +
2084 'DECLARE @blocker BIT;
2085 SET @blocker = 0;
2086 DECLARE @i INT;
2087 SET @i = 2147483647;
2088
2089 DECLARE @sessions TABLE
2090 (
2091 session_id SMALLINT NOT NULL,
2092 request_id INT NOT NULL,
2093 login_time DATETIME,
2094 last_request_end_time DATETIME,
2095 status VARCHAR(30),
2096 statement_start_offset INT,
2097 statement_end_offset INT,
2098 sql_handle BINARY(20),
2099 host_name NVARCHAR(128),
2100 login_name NVARCHAR(128),
2101 program_name NVARCHAR(128),
2102 database_id SMALLINT,
2103 memory_usage INT,
2104 open_tran_count SMALLINT,
2105 ' +
2106 CASE
2107 WHEN
2108 (
2109 @get_task_info <> 0
2110 OR @find_block_leaders = 1
2111 ) THEN
2112 'wait_type NVARCHAR(32),
2113 wait_resource NVARCHAR(256),
2114 wait_time BIGINT,
2115 '
2116 ELSE
2117 ''
2118 END +
2119 'blocked SMALLINT,
2120 is_user_process BIT,
2121 cmd VARCHAR(32),
2122 PRIMARY KEY CLUSTERED (session_id, request_id) WITH (IGNORE_DUP_KEY = ON)
2123 );
2124
2125 DECLARE @blockers TABLE
2126 (
2127 session_id INT NOT NULL PRIMARY KEY
2128 );
2129
2130 BLOCKERS:;
2131
2132 INSERT @sessions
2133 (
2134 session_id,
2135 request_id,
2136 login_time,
2137 last_request_end_time,
2138 status,
2139 statement_start_offset,
2140 statement_end_offset,
2141 sql_handle,
2142 host_name,
2143 login_name,
2144 program_name,
2145 database_id,
2146 memory_usage,
2147 open_tran_count,
2148 ' +
2149 CASE
2150 WHEN
2151 (
2152 @get_task_info <> 0
2153 OR @find_block_leaders = 1
2154 ) THEN
2155 'wait_type,
2156 wait_resource,
2157 wait_time,
2158 '
2159 ELSE
2160 ''
2161 END +
2162 'blocked,
2163 is_user_process,
2164 cmd
2165 )
2166 SELECT TOP(@i)
2167 spy.session_id,
2168 spy.request_id,
2169 spy.login_time,
2170 spy.last_request_end_time,
2171 spy.status,
2172 spy.statement_start_offset,
2173 spy.statement_end_offset,
2174 spy.sql_handle,
2175 spy.host_name,
2176 spy.login_name,
2177 spy.program_name,
2178 spy.database_id,
2179 spy.memory_usage,
2180 spy.open_tran_count,
2181 ' +
2182 CASE
2183 WHEN
2184 (
2185 @get_task_info <> 0
2186 OR @find_block_leaders = 1
2187 ) THEN
2188 'spy.wait_type,
2189 CASE
2190 WHEN
2191 spy.wait_type LIKE N''PAGE%LATCH_%''
2192 OR spy.wait_type = N''CXPACKET''
2193 OR spy.wait_type LIKE N''LATCH[_]%''
2194 OR spy.wait_type = N''OLEDB'' THEN
2195 spy.wait_resource
2196 ELSE
2197 NULL
2198 END AS wait_resource,
2199 spy.wait_time,
2200 '
2201 ELSE
2202 ''
2203 END +
2204 'spy.blocked,
2205 spy.is_user_process,
2206 spy.cmd
2207 FROM
2208 (
2209 SELECT TOP(@i)
2210 spx.*,
2211 ' +
2212 CASE
2213 WHEN
2214 (
2215 @get_task_info <> 0
2216 OR @find_block_leaders = 1
2217 ) THEN
2218 'ROW_NUMBER() OVER
2219 (
2220 PARTITION BY
2221 spx.session_id,
2222 spx.request_id
2223 ORDER BY
2224 CASE
2225 WHEN spx.wait_type LIKE N''LCK[_]%'' THEN
2226 1
2227 ELSE
2228 99
2229 END,
2230 spx.wait_time DESC,
2231 spx.blocked DESC
2232 ) AS r
2233 '
2234 ELSE
2235 '1 AS r
2236 '
2237 END +
2238 'FROM
2239 (
2240 SELECT TOP(@i)
2241 sp0.session_id,
2242 sp0.request_id,
2243 sp0.login_time,
2244 sp0.last_request_end_time,
2245 LOWER(sp0.status) AS status,
2246 CASE
2247 WHEN sp0.cmd = ''CREATE INDEX'' THEN
2248 0
2249 ELSE
2250 sp0.stmt_start
2251 END AS statement_start_offset,
2252 CASE
2253 WHEN sp0.cmd = N''CREATE INDEX'' THEN
2254 -1
2255 ELSE
2256 COALESCE(NULLIF(sp0.stmt_end, 0), -1)
2257 END AS statement_end_offset,
2258 sp0.sql_handle,
2259 sp0.host_name,
2260 sp0.login_name,
2261 sp0.program_name,
2262 sp0.database_id,
2263 sp0.memory_usage,
2264 sp0.open_tran_count,
2265 ' +
2266 CASE
2267 WHEN
2268 (
2269 @get_task_info <> 0
2270 OR @find_block_leaders = 1
2271 ) THEN
2272 'CASE
2273 WHEN sp0.wait_time > 0 AND sp0.wait_type <> N''CXPACKET'' THEN
2274 sp0.wait_type
2275 ELSE
2276 NULL
2277 END AS wait_type,
2278 CASE
2279 WHEN sp0.wait_time > 0 AND sp0.wait_type <> N''CXPACKET'' THEN
2280 sp0.wait_resource
2281 ELSE
2282 NULL
2283 END AS wait_resource,
2284 CASE
2285 WHEN sp0.wait_type <> N''CXPACKET'' THEN
2286 sp0.wait_time
2287 ELSE
2288 0
2289 END AS wait_time,
2290 '
2291 ELSE
2292 ''
2293 END +
2294 'sp0.blocked,
2295 sp0.is_user_process,
2296 sp0.cmd
2297 FROM
2298 (
2299 SELECT TOP(@i)
2300 sp1.session_id,
2301 sp1.request_id,
2302 sp1.login_time,
2303 sp1.last_request_end_time,
2304 sp1.status,
2305 sp1.cmd,
2306 sp1.stmt_start,
2307 sp1.stmt_end,
2308 MAX(NULLIF(sp1.sql_handle, 0x00)) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS sql_handle,
2309 sp1.host_name,
2310 MAX(sp1.login_name) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS login_name,
2311 sp1.program_name,
2312 sp1.database_id,
2313 MAX(sp1.memory_usage) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS memory_usage,
2314 MAX(sp1.open_tran_count) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS open_tran_count,
2315 sp1.wait_type,
2316 sp1.wait_resource,
2317 sp1.wait_time,
2318 sp1.blocked,
2319 sp1.hostprocess,
2320 sp1.is_user_process
2321 FROM
2322 (
2323 SELECT TOP(@i)
2324 sp2.spid AS session_id,
2325 CASE sp2.status
2326 WHEN ''sleeping'' THEN
2327 CONVERT(INT, 0)
2328 ELSE
2329 sp2.request_id
2330 END AS request_id,
2331 MAX(sp2.login_time) AS login_time,
2332 MAX(sp2.last_batch) AS last_request_end_time,
2333 MAX(CONVERT(VARCHAR(30), RTRIM(sp2.status)) COLLATE Latin1_General_Bin2) AS status,
2334 MAX(CONVERT(VARCHAR(32), RTRIM(sp2.cmd)) COLLATE Latin1_General_Bin2) AS cmd,
2335 MAX(sp2.stmt_start) AS stmt_start,
2336 MAX(sp2.stmt_end) AS stmt_end,
2337 MAX(sp2.sql_handle) AS sql_handle,
2338 MAX(CONVERT(sysname, RTRIM(sp2.hostname)) COLLATE SQL_Latin1_General_CP1_CI_AS) AS host_name,
2339 MAX(CONVERT(sysname, RTRIM(sp2.loginame)) COLLATE SQL_Latin1_General_CP1_CI_AS) AS login_name,
2340 MAX
2341 (
2342 CASE
2343 WHEN blk.queue_id IS NOT NULL THEN
2344 N''Service Broker
2345 database_id: '' + CONVERT(NVARCHAR, blk.database_id) +
2346 N'' queue_id: '' + CONVERT(NVARCHAR, blk.queue_id)
2347 ELSE
2348 CONVERT
2349 (
2350 sysname,
2351 RTRIM(sp2.program_name)
2352 )
2353 END COLLATE SQL_Latin1_General_CP1_CI_AS
2354 ) AS program_name,
2355 MAX(sp2.dbid) AS database_id,
2356 MAX(sp2.memusage) AS memory_usage,
2357 MAX(sp2.open_tran) AS open_tran_count,
2358 RTRIM(sp2.lastwaittype) AS wait_type,
2359 RTRIM(sp2.waitresource) AS wait_resource,
2360 MAX(sp2.waittime) AS wait_time,
2361 COALESCE(NULLIF(sp2.blocked, sp2.spid), 0) AS blocked,
2362 MAX
2363 (
2364 CASE
2365 WHEN blk.session_id = sp2.spid THEN
2366 ''blocker''
2367 ELSE
2368 RTRIM(sp2.hostprocess)
2369 END
2370 ) AS hostprocess,
2371 CONVERT
2372 (
2373 BIT,
2374 MAX
2375 (
2376 CASE
2377 WHEN sp2.hostprocess > '''' THEN
2378 1
2379 ELSE
2380 0
2381 END
2382 )
2383 ) AS is_user_process
2384 FROM
2385 (
2386 SELECT TOP(@i)
2387 session_id,
2388 CONVERT(INT, NULL) AS queue_id,
2389 CONVERT(INT, NULL) AS database_id
2390 FROM @blockers
2391
2392 UNION ALL
2393
2394 SELECT TOP(@i)
2395 CONVERT(SMALLINT, 0),
2396 CONVERT(INT, NULL) AS queue_id,
2397 CONVERT(INT, NULL) AS database_id
2398 WHERE
2399 @blocker = 0
2400
2401 UNION ALL
2402
2403 SELECT TOP(@i)
2404 CONVERT(SMALLINT, spid),
2405 queue_id,
2406 database_id
2407 FROM sys.dm_broker_activated_tasks
2408 WHERE
2409 @blocker = 0
2410 ) AS blk
2411 INNER JOIN sys.sysprocesses AS sp2 ON
2412 sp2.spid = blk.session_id
2413 OR
2414 (
2415 blk.session_id = 0
2416 AND @blocker = 0
2417 )
2418 ' +
2419 CASE
2420 WHEN
2421 (
2422 @get_task_info = 0
2423 AND @find_block_leaders = 0
2424 ) THEN
2425 'WHERE
2426 sp2.ecid = 0
2427 '
2428 ELSE
2429 ''
2430 END +
2431 'GROUP BY
2432 sp2.spid,
2433 CASE sp2.status
2434 WHEN ''sleeping'' THEN
2435 CONVERT(INT, 0)
2436 ELSE
2437 sp2.request_id
2438 END,
2439 RTRIM(sp2.lastwaittype),
2440 RTRIM(sp2.waitresource),
2441 COALESCE(NULLIF(sp2.blocked, sp2.spid), 0)
2442 ) AS sp1
2443 ) AS sp0
2444 WHERE
2445 @blocker = 1
2446 OR
2447 (1=1
2448 ' +
2449 --inclusive filter
2450 CASE
2451 WHEN @filter <> '' THEN
2452 CASE @filter_type
2453 WHEN 'session' THEN
2454 CASE
2455 WHEN CONVERT(SMALLINT, @filter) <> 0 THEN
2456 'AND sp0.session_id = CONVERT(SMALLINT, @filter)
2457 '
2458 ELSE
2459 ''
2460 END
2461 WHEN 'program' THEN
2462 'AND sp0.program_name LIKE @filter
2463 '
2464 WHEN 'login' THEN
2465 'AND sp0.login_name LIKE @filter
2466 '
2467 WHEN 'host' THEN
2468 'AND sp0.host_name LIKE @filter
2469 '
2470 WHEN 'database' THEN
2471 'AND DB_NAME(sp0.database_id) LIKE @filter
2472 '
2473 ELSE
2474 ''
2475 END
2476 ELSE
2477 ''
2478 END +
2479 --exclusive filter
2480 CASE
2481 WHEN @not_filter <> '' THEN
2482 CASE @not_filter_type
2483 WHEN 'session' THEN
2484 CASE
2485 WHEN CONVERT(SMALLINT, @not_filter) <> 0 THEN
2486 'AND sp0.session_id <> CONVERT(SMALLINT, @not_filter)
2487 '
2488 ELSE
2489 ''
2490 END
2491 WHEN 'program' THEN
2492 'AND sp0.program_name NOT LIKE @not_filter
2493 '
2494 WHEN 'login' THEN
2495 'AND sp0.login_name NOT LIKE @not_filter
2496 '
2497 WHEN 'host' THEN
2498 'AND sp0.host_name NOT LIKE @not_filter
2499 '
2500 WHEN 'database' THEN
2501 'AND DB_NAME(sp0.database_id) NOT LIKE @not_filter
2502 '
2503 ELSE
2504 ''
2505 END
2506 ELSE
2507 ''
2508 END +
2509 CASE @show_own_spid
2510 WHEN 1 THEN
2511 ''
2512 ELSE
2513 'AND sp0.session_id <> @@spid
2514 '
2515 END +
2516 CASE
2517 WHEN @show_system_spids = 0 THEN
2518 'AND sp0.hostprocess > ''''
2519 '
2520 ELSE
2521 ''
2522 END +
2523 CASE @show_sleeping_spids
2524 WHEN 0 THEN
2525 'AND sp0.status <> ''sleeping''
2526 '
2527 WHEN 1 THEN
2528 'AND
2529 (
2530 sp0.status <> ''sleeping''
2531 OR sp0.open_tran_count > 0
2532 )
2533 '
2534 ELSE
2535 ''
2536 END +
2537 ')
2538 ) AS spx
2539 ) AS spy
2540 WHERE
2541 spy.r = 1;
2542 ' +
2543 CASE @recursion
2544 WHEN 1 THEN
2545 'IF @@ROWCOUNT > 0
2546 BEGIN;
2547 INSERT @blockers
2548 (
2549 session_id
2550 )
2551 SELECT TOP(@i)
2552 blocked
2553 FROM @sessions
2554 WHERE
2555 NULLIF(blocked, 0) IS NOT NULL
2556
2557 EXCEPT
2558
2559 SELECT TOP(@i)
2560 session_id
2561 FROM @sessions;
2562 ' +
2563
2564 CASE
2565 WHEN
2566 (
2567 @get_task_info > 0
2568 OR @find_block_leaders = 1
2569 ) THEN
2570 'IF @@ROWCOUNT > 0
2571 BEGIN;
2572 SET @blocker = 1;
2573 GOTO BLOCKERS;
2574 END;
2575 '
2576 ELSE
2577 ''
2578 END +
2579 'END;
2580 '
2581 ELSE
2582 ''
2583 END +
2584 'SELECT TOP(@i)
2585 @recursion AS recursion,
2586 x.session_id,
2587 x.request_id,
2588 DENSE_RANK() OVER
2589 (
2590 ORDER BY
2591 x.session_id
2592 ) AS session_number,
2593 ' +
2594 CASE
2595 WHEN @output_column_list LIKE '%|[dd hh:mm:ss.mss|]%' ESCAPE '|' THEN
2596 'x.elapsed_time '
2597 ELSE
2598 '0 '
2599 END +
2600 'AS elapsed_time,
2601 ' +
2602 CASE
2603 WHEN
2604 (
2605 @output_column_list LIKE '%|[dd hh:mm:ss.mss (avg)|]%' ESCAPE '|' OR
2606 @output_column_list LIKE '%|[avg_elapsed_time|]%' ESCAPE '|'
2607 )
2608 AND @recursion = 1
2609 THEN
2610 'x.avg_elapsed_time / 1000 '
2611 ELSE
2612 'NULL '
2613 END +
2614 'AS avg_elapsed_time,
2615 ' +
2616 CASE
2617 WHEN
2618 @output_column_list LIKE '%|[physical_io|]%' ESCAPE '|'
2619 OR @output_column_list LIKE '%|[physical_io_delta|]%' ESCAPE '|'
2620 THEN
2621 'x.physical_io '
2622 ELSE
2623 'NULL '
2624 END +
2625 'AS physical_io,
2626 ' +
2627 CASE
2628 WHEN
2629 @output_column_list LIKE '%|[reads|]%' ESCAPE '|'
2630 OR @output_column_list LIKE '%|[reads_delta|]%' ESCAPE '|'
2631 THEN
2632 'x.reads '
2633 ELSE
2634 '0 '
2635 END +
2636 'AS reads,
2637 ' +
2638 CASE
2639 WHEN
2640 @output_column_list LIKE '%|[physical_reads|]%' ESCAPE '|'
2641 OR @output_column_list LIKE '%|[physical_reads_delta|]%' ESCAPE '|'
2642 THEN
2643 'x.physical_reads '
2644 ELSE
2645 '0 '
2646 END +
2647 'AS physical_reads,
2648 ' +
2649 CASE
2650 WHEN
2651 @output_column_list LIKE '%|[writes|]%' ESCAPE '|'
2652 OR @output_column_list LIKE '%|[writes_delta|]%' ESCAPE '|'
2653 THEN
2654 'x.writes '
2655 ELSE
2656 '0 '
2657 END +
2658 'AS writes,
2659 ' +
2660 CASE
2661 WHEN
2662 @output_column_list LIKE '%|[tempdb_allocations|]%' ESCAPE '|'
2663 OR @output_column_list LIKE '%|[tempdb_allocations_delta|]%' ESCAPE '|'
2664 THEN
2665 'x.tempdb_allocations '
2666 ELSE
2667 '0 '
2668 END +
2669 'AS tempdb_allocations,
2670 ' +
2671 CASE
2672 WHEN
2673 @output_column_list LIKE '%|[tempdb_current|]%' ESCAPE '|'
2674 OR @output_column_list LIKE '%|[tempdb_current_delta|]%' ESCAPE '|'
2675 THEN
2676 'x.tempdb_current '
2677 ELSE
2678 '0 '
2679 END +
2680 'AS tempdb_current,
2681 ' +
2682 CASE
2683 WHEN
2684 @output_column_list LIKE '%|[CPU|]%' ESCAPE '|'
2685 OR @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|'
2686 THEN
2687 'x.CPU '
2688 ELSE
2689 '0 '
2690 END +
2691 'AS CPU,
2692 ' +
2693 CASE
2694 WHEN
2695 @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|'
2696 AND @get_task_info = 2
2697 THEN
2698 'x.thread_CPU_snapshot '
2699 ELSE
2700 '0 '
2701 END +
2702 'AS thread_CPU_snapshot,
2703 ' +
2704 CASE
2705 WHEN
2706 @output_column_list LIKE '%|[context_switches|]%' ESCAPE '|'
2707 OR @output_column_list LIKE '%|[context_switches_delta|]%' ESCAPE '|'
2708 THEN
2709 'x.context_switches '
2710 ELSE
2711 'NULL '
2712 END +
2713 'AS context_switches,
2714 ' +
2715 CASE
2716 WHEN
2717 @output_column_list LIKE '%|[used_memory|]%' ESCAPE '|'
2718 OR @output_column_list LIKE '%|[used_memory_delta|]%' ESCAPE '|'
2719 THEN
2720 'x.used_memory '
2721 ELSE
2722 '0 '
2723 END +
2724 'AS used_memory,
2725 ' +
2726 CASE
2727 WHEN
2728 @output_column_list LIKE '%|[tasks|]%' ESCAPE '|'
2729 AND @recursion = 1
2730 THEN
2731 'x.tasks '
2732 ELSE
2733 'NULL '
2734 END +
2735 'AS tasks,
2736 ' +
2737 CASE
2738 WHEN
2739 (
2740 @output_column_list LIKE '%|[status|]%' ESCAPE '|'
2741 OR @output_column_list LIKE '%|[sql_command|]%' ESCAPE '|'
2742 )
2743 AND @recursion = 1
2744 THEN
2745 'x.status '
2746 ELSE
2747 ''''' '
2748 END +
2749 'AS status,
2750 ' +
2751 CASE
2752 WHEN
2753 @output_column_list LIKE '%|[wait_info|]%' ESCAPE '|'
2754 AND @recursion = 1
2755 THEN
2756 CASE @get_task_info
2757 WHEN 2 THEN
2758 'COALESCE(x.task_wait_info, x.sys_wait_info) '
2759 ELSE
2760 'x.sys_wait_info '
2761 END
2762 ELSE
2763 'NULL '
2764 END +
2765 'AS wait_info,
2766 ' +
2767 CASE
2768 WHEN
2769 (
2770 @output_column_list LIKE '%|[tran_start_time|]%' ESCAPE '|'
2771 OR @output_column_list LIKE '%|[tran_log_writes|]%' ESCAPE '|'
2772 )
2773 AND @recursion = 1
2774 THEN
2775 'x.transaction_id '
2776 ELSE
2777 'NULL '
2778 END +
2779 'AS transaction_id,
2780 ' +
2781 CASE
2782 WHEN
2783 @output_column_list LIKE '%|[open_tran_count|]%' ESCAPE '|'
2784 AND @recursion = 1
2785 THEN
2786 'x.open_tran_count '
2787 ELSE
2788 'NULL '
2789 END +
2790 'AS open_tran_count,
2791 ' +
2792 CASE
2793 WHEN
2794 @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|'
2795 AND @recursion = 1
2796 THEN
2797 'x.sql_handle '
2798 ELSE
2799 'NULL '
2800 END +
2801 'AS sql_handle,
2802 ' +
2803 CASE
2804 WHEN
2805 (
2806 @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|'
2807 OR @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|'
2808 )
2809 AND @recursion = 1
2810 THEN
2811 'x.statement_start_offset '
2812 ELSE
2813 'NULL '
2814 END +
2815 'AS statement_start_offset,
2816 ' +
2817 CASE
2818 WHEN
2819 (
2820 @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|'
2821 OR @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|'
2822 )
2823 AND @recursion = 1
2824 THEN
2825 'x.statement_end_offset '
2826 ELSE
2827 'NULL '
2828 END +
2829 'AS statement_end_offset,
2830 ' +
2831 'NULL AS sql_text,
2832 ' +
2833 CASE
2834 WHEN
2835 @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|'
2836 AND @recursion = 1
2837 THEN
2838 'x.plan_handle '
2839 ELSE
2840 'NULL '
2841 END +
2842 'AS plan_handle,
2843 ' +
2844 CASE
2845 WHEN
2846 @output_column_list LIKE '%|[blocking_session_id|]%' ESCAPE '|'
2847 AND @recursion = 1
2848 THEN
2849 'NULLIF(x.blocking_session_id, 0) '
2850 ELSE
2851 'NULL '
2852 END +
2853 'AS blocking_session_id,
2854 ' +
2855 CASE
2856 WHEN
2857 @output_column_list LIKE '%|[percent_complete|]%' ESCAPE '|'
2858 AND @recursion = 1
2859 THEN
2860 'x.percent_complete '
2861 ELSE
2862 'NULL '
2863 END +
2864 'AS percent_complete,
2865 ' +
2866 CASE
2867 WHEN
2868 @output_column_list LIKE '%|[host_name|]%' ESCAPE '|'
2869 AND @recursion = 1
2870 THEN
2871 'x.host_name '
2872 ELSE
2873 ''''' '
2874 END +
2875 'AS host_name,
2876 ' +
2877 CASE
2878 WHEN
2879 @output_column_list LIKE '%|[login_name|]%' ESCAPE '|'
2880 AND @recursion = 1
2881 THEN
2882 'x.login_name '
2883 ELSE
2884 ''''' '
2885 END +
2886 'AS login_name,
2887 ' +
2888 CASE
2889 WHEN
2890 @output_column_list LIKE '%|[database_name|]%' ESCAPE '|'
2891 AND @recursion = 1
2892 THEN
2893 'DB_NAME(x.database_id) '
2894 ELSE
2895 'NULL '
2896 END +
2897 'AS database_name,
2898 ' +
2899 CASE
2900 WHEN
2901 @output_column_list LIKE '%|[program_name|]%' ESCAPE '|'
2902 AND @recursion = 1
2903 THEN
2904 'x.program_name '
2905 ELSE
2906 ''''' '
2907 END +
2908 'AS program_name,
2909 ' +
2910 CASE
2911 WHEN
2912 @output_column_list LIKE '%|[additional_info|]%' ESCAPE '|'
2913 AND @recursion = 1
2914 THEN
2915 '(
2916 SELECT TOP(@i)
2917 x.text_size,
2918 x.language,
2919 x.date_format,
2920 x.date_first,
2921 CASE x.quoted_identifier
2922 WHEN 0 THEN ''OFF''
2923 WHEN 1 THEN ''ON''
2924 END AS quoted_identifier,
2925 CASE x.arithabort
2926 WHEN 0 THEN ''OFF''
2927 WHEN 1 THEN ''ON''
2928 END AS arithabort,
2929 CASE x.ansi_null_dflt_on
2930 WHEN 0 THEN ''OFF''
2931 WHEN 1 THEN ''ON''
2932 END AS ansi_null_dflt_on,
2933 CASE x.ansi_defaults
2934 WHEN 0 THEN ''OFF''
2935 WHEN 1 THEN ''ON''
2936 END AS ansi_defaults,
2937 CASE x.ansi_warnings
2938 WHEN 0 THEN ''OFF''
2939 WHEN 1 THEN ''ON''
2940 END AS ansi_warnings,
2941 CASE x.ansi_padding
2942 WHEN 0 THEN ''OFF''
2943 WHEN 1 THEN ''ON''
2944 END AS ansi_padding,
2945 CASE ansi_nulls
2946 WHEN 0 THEN ''OFF''
2947 WHEN 1 THEN ''ON''
2948 END AS ansi_nulls,
2949 CASE x.concat_null_yields_null
2950 WHEN 0 THEN ''OFF''
2951 WHEN 1 THEN ''ON''
2952 END AS concat_null_yields_null,
2953 CASE x.transaction_isolation_level
2954 WHEN 0 THEN ''Unspecified''
2955 WHEN 1 THEN ''ReadUncomitted''
2956 WHEN 2 THEN ''ReadCommitted''
2957 WHEN 3 THEN ''Repeatable''
2958 WHEN 4 THEN ''Serializable''
2959 WHEN 5 THEN ''Snapshot''
2960 END AS transaction_isolation_level,
2961 x.lock_timeout,
2962 x.deadlock_priority,
2963 x.row_count,
2964 x.command_type,
2965 ' +
2966 CASE
2967 WHEN @output_column_list LIKE '%|[program_name|]%' ESCAPE '|' THEN
2968 '(
2969 SELECT TOP(1)
2970 CONVERT(uniqueidentifier, CONVERT(XML, '''').value(''xs:hexBinary( substring(sql:column("agent_info.job_id_string"), 0) )'', ''binary(16)'')) AS job_id,
2971 agent_info.step_id,
2972 (
2973 SELECT TOP(1)
2974 NULL
2975 FOR XML
2976 PATH(''job_name''),
2977 TYPE
2978 ),
2979 (
2980 SELECT TOP(1)
2981 NULL
2982 FOR XML
2983 PATH(''step_name''),
2984 TYPE
2985 )
2986 FROM
2987 (
2988 SELECT TOP(1)
2989 SUBSTRING(x.program_name, CHARINDEX(''0x'', x.program_name) + 2, 32) AS job_id_string,
2990 SUBSTRING(x.program_name, CHARINDEX('': Step '', x.program_name) + 7, CHARINDEX('')'', x.program_name, CHARINDEX('': Step '', x.program_name)) - (CHARINDEX('': Step '', x.program_name) + 7)) AS step_id
2991 WHERE
2992 x.program_name LIKE N''SQLAgent - TSQL JobStep (Job 0x%''
2993 ) AS agent_info
2994 FOR XML
2995 PATH(''agent_job_info''),
2996 TYPE
2997 ),
2998 '
2999 ELSE ''
3000 END +
3001 CASE
3002 WHEN @get_task_info = 2 THEN
3003 'CONVERT(XML, x.block_info) AS block_info,
3004 '
3005 ELSE
3006 ''
3007 END +
3008 'x.host_process_id
3009 FOR XML
3010 PATH(''additional_info''),
3011 TYPE
3012 ) '
3013 ELSE
3014 'NULL '
3015 END +
3016 'AS additional_info,
3017 x.start_time,
3018 ' +
3019 CASE
3020 WHEN
3021 @output_column_list LIKE '%|[login_time|]%' ESCAPE '|'
3022 AND @recursion = 1
3023 THEN
3024 'x.login_time '
3025 ELSE
3026 'NULL '
3027 END +
3028 'AS login_time,
3029 x.last_request_start_time
3030 FROM
3031 (
3032 SELECT TOP(@i)
3033 y.*,
3034 CASE
3035 WHEN DATEDIFF(day, y.start_time, GETDATE()) > 24 THEN
3036 DATEDIFF(second, GETDATE(), y.start_time)
3037 ELSE DATEDIFF(ms, y.start_time, GETDATE())
3038 END AS elapsed_time,
3039 COALESCE(tempdb_info.tempdb_allocations, 0) AS tempdb_allocations,
3040 COALESCE
3041 (
3042 CASE
3043 WHEN tempdb_info.tempdb_current < 0 THEN 0
3044 ELSE tempdb_info.tempdb_current
3045 END,
3046 0
3047 ) AS tempdb_current,
3048 ' +
3049 CASE
3050 WHEN
3051 (
3052 @get_task_info <> 0
3053 OR @find_block_leaders = 1
3054 ) THEN
3055 'N''('' + CONVERT(NVARCHAR, y.wait_duration_ms) + N''ms)'' +
3056 y.wait_type +
3057 CASE
3058 WHEN y.wait_type LIKE N''PAGE%LATCH_%'' THEN
3059 N'':'' +
3060 COALESCE(DB_NAME(CONVERT(INT, LEFT(y.resource_description, CHARINDEX(N'':'', y.resource_description) - 1))), N''(null)'') +
3061 N'':'' +
3062 SUBSTRING(y.resource_description, CHARINDEX(N'':'', y.resource_description) + 1, LEN(y.resource_description) - CHARINDEX(N'':'', REVERSE(y.resource_description)) - CHARINDEX(N'':'', y.resource_description)) +
3063 N''('' +
3064 CASE
3065 WHEN
3066 CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 1 OR
3067 CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) % 8088 = 0
3068 THEN
3069 N''PFS''
3070 WHEN
3071 CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 2 OR
3072 CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) % 511232 = 0
3073 THEN
3074 N''GAM''
3075 WHEN
3076 CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 3 OR
3077 CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) % 511233 = 0
3078 THEN
3079 N''SGAM''
3080 WHEN
3081 CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 6 OR
3082 CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) % 511238 = 0
3083 THEN
3084 N''DCM''
3085 WHEN
3086 CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 7 OR
3087 CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) % 511239 = 0
3088 THEN
3089 N''BCM''
3090 ELSE
3091 N''*''
3092 END +
3093 N'')''
3094 WHEN y.wait_type = N''CXPACKET'' THEN
3095 N'':'' + SUBSTRING(y.resource_description, CHARINDEX(N''nodeId'', y.resource_description) + 7, 4)
3096 WHEN y.wait_type LIKE N''LATCH[_]%'' THEN
3097 N'' ['' + LEFT(y.resource_description, COALESCE(NULLIF(CHARINDEX(N'' '', y.resource_description), 0), LEN(y.resource_description) + 1) - 1) + N'']''
3098 WHEN
3099 y.wait_type = N''OLEDB''
3100 AND y.resource_description LIKE N''%(SPID=%)'' THEN
3101 N''['' + LEFT(y.resource_description, CHARINDEX(N''(SPID='', y.resource_description) - 2) +
3102 N'':'' + SUBSTRING(y.resource_description, CHARINDEX(N''(SPID='', y.resource_description) + 6, CHARINDEX(N'')'', y.resource_description, (CHARINDEX(N''(SPID='', y.resource_description) + 6)) - (CHARINDEX(N''(SPID='', y.resource_description) + 6)) + '']''
3103 ELSE
3104 N''''
3105 END COLLATE Latin1_General_Bin2 AS sys_wait_info,
3106 '
3107 ELSE
3108 ''
3109 END +
3110 CASE
3111 WHEN @get_task_info = 2 THEN
3112 'tasks.physical_io,
3113 tasks.context_switches,
3114 tasks.tasks,
3115 tasks.block_info,
3116 tasks.wait_info AS task_wait_info,
3117 tasks.thread_CPU_snapshot,
3118 '
3119 ELSE
3120 ''
3121 END +
3122 CASE
3123 WHEN NOT (@get_avg_time = 1 AND @recursion = 1) THEN
3124 'CONVERT(INT, NULL) '
3125 ELSE
3126 'qs.total_elapsed_time / qs.execution_count '
3127 END +
3128 'AS avg_elapsed_time
3129 FROM
3130 (
3131 SELECT TOP(@i)
3132 sp.session_id,
3133 sp.request_id,
3134 COALESCE(r.logical_reads, s.logical_reads) AS reads,
3135 COALESCE(r.reads, s.reads) AS physical_reads,
3136 COALESCE(r.writes, s.writes) AS writes,
3137 COALESCE(r.CPU_time, s.CPU_time) AS CPU,
3138 sp.memory_usage + COALESCE(r.granted_query_memory, 0) AS used_memory,
3139 LOWER(sp.status) AS status,
3140 COALESCE(r.sql_handle, sp.sql_handle) AS sql_handle,
3141 COALESCE(r.statement_start_offset, sp.statement_start_offset) AS statement_start_offset,
3142 COALESCE(r.statement_end_offset, sp.statement_end_offset) AS statement_end_offset,
3143 ' +
3144 CASE
3145 WHEN
3146 (
3147 @get_task_info <> 0
3148 OR @find_block_leaders = 1
3149 ) THEN
3150 'sp.wait_type COLLATE Latin1_General_Bin2 AS wait_type,
3151 sp.wait_resource COLLATE Latin1_General_Bin2 AS resource_description,
3152 sp.wait_time AS wait_duration_ms,
3153 '
3154 ELSE
3155 ''
3156 END +
3157 'NULLIF(sp.blocked, 0) AS blocking_session_id,
3158 r.plan_handle,
3159 NULLIF(r.percent_complete, 0) AS percent_complete,
3160 sp.host_name,
3161 sp.login_name,
3162 sp.program_name,
3163 s.host_process_id,
3164 COALESCE(r.text_size, s.text_size) AS text_size,
3165 COALESCE(r.language, s.language) AS language,
3166 COALESCE(r.date_format, s.date_format) AS date_format,
3167 COALESCE(r.date_first, s.date_first) AS date_first,
3168 COALESCE(r.quoted_identifier, s.quoted_identifier) AS quoted_identifier,
3169 COALESCE(r.arithabort, s.arithabort) AS arithabort,
3170 COALESCE(r.ansi_null_dflt_on, s.ansi_null_dflt_on) AS ansi_null_dflt_on,
3171 COALESCE(r.ansi_defaults, s.ansi_defaults) AS ansi_defaults,
3172 COALESCE(r.ansi_warnings, s.ansi_warnings) AS ansi_warnings,
3173 COALESCE(r.ansi_padding, s.ansi_padding) AS ansi_padding,
3174 COALESCE(r.ansi_nulls, s.ansi_nulls) AS ansi_nulls,
3175 COALESCE(r.concat_null_yields_null, s.concat_null_yields_null) AS concat_null_yields_null,
3176 COALESCE(r.transaction_isolation_level, s.transaction_isolation_level) AS transaction_isolation_level,
3177 COALESCE(r.lock_timeout, s.lock_timeout) AS lock_timeout,
3178 COALESCE(r.deadlock_priority, s.deadlock_priority) AS deadlock_priority,
3179 COALESCE(r.row_count, s.row_count) AS row_count,
3180 COALESCE(r.command, sp.cmd) AS command_type,
3181 COALESCE
3182 (
3183 CASE
3184 WHEN
3185 (
3186 s.is_user_process = 0
3187 AND r.total_elapsed_time >= 0
3188 ) THEN
3189 DATEADD
3190 (
3191 ms,
3192 1000 * (DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())) / 500) - DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())),
3193 DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())
3194 )
3195 END,
3196 NULLIF(COALESCE(r.start_time, sp.last_request_end_time), CONVERT(DATETIME, ''19000101'', 112)),
3197 (
3198 SELECT TOP(1)
3199 DATEADD(second, -(ms_ticks / 1000), GETDATE())
3200 FROM sys.dm_os_sys_info
3201 )
3202 ) AS start_time,
3203 sp.login_time,
3204 CASE
3205 WHEN s.is_user_process = 1 THEN
3206 s.last_request_start_time
3207 ELSE
3208 COALESCE
3209 (
3210 DATEADD
3211 (
3212 ms,
3213 1000 * (DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())) / 500) - DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())),
3214 DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())
3215 ),
3216 s.last_request_start_time
3217 )
3218 END AS last_request_start_time,
3219 r.transaction_id,
3220 sp.database_id,
3221 sp.open_tran_count
3222 FROM @sessions AS sp
3223 LEFT OUTER LOOP JOIN sys.dm_exec_sessions AS s ON
3224 s.session_id = sp.session_id
3225 AND s.login_time = sp.login_time
3226 LEFT OUTER LOOP JOIN sys.dm_exec_requests AS r ON
3227 sp.status <> ''sleeping''
3228 AND r.session_id = sp.session_id
3229 AND r.request_id = sp.request_id
3230 AND
3231 (
3232 (
3233 s.is_user_process = 0
3234 AND sp.is_user_process = 0
3235 )
3236 OR
3237 (
3238 r.start_time = s.last_request_start_time
3239 AND s.last_request_end_time = sp.last_request_end_time
3240 )
3241 )
3242 ) AS y
3243 ' +
3244 CASE
3245 WHEN @get_task_info = 2 THEN
3246 CONVERT(VARCHAR(MAX), '') +
3247 'LEFT OUTER HASH JOIN
3248 (
3249 SELECT TOP(@i)
3250 task_nodes.task_node.value(''(session_id/text())[1]'', ''SMALLINT'') AS session_id,
3251 task_nodes.task_node.value(''(request_id/text())[1]'', ''INT'') AS request_id,
3252 task_nodes.task_node.value(''(physical_io/text())[1]'', ''BIGINT'') AS physical_io,
3253 task_nodes.task_node.value(''(context_switches/text())[1]'', ''BIGINT'') AS context_switches,
3254 task_nodes.task_node.value(''(tasks/text())[1]'', ''INT'') AS tasks,
3255 task_nodes.task_node.value(''(block_info/text())[1]'', ''NVARCHAR(4000)'') AS block_info,
3256 task_nodes.task_node.value(''(waits/text())[1]'', ''NVARCHAR(4000)'') AS wait_info,
3257 task_nodes.task_node.value(''(thread_CPU_snapshot/text())[1]'', ''BIGINT'') AS thread_CPU_snapshot
3258 FROM
3259 (
3260 SELECT TOP(@i)
3261 CONVERT
3262 (
3263 XML,
3264 REPLACE
3265 (
3266 CONVERT(NVARCHAR(MAX), tasks_raw.task_xml_raw) COLLATE Latin1_General_Bin2,
3267 N''</waits></tasks><tasks><waits>'',
3268 N'', ''
3269 )
3270 ) AS task_xml
3271 FROM
3272 (
3273 SELECT TOP(@i)
3274 CASE waits.r
3275 WHEN 1 THEN
3276 waits.session_id
3277 ELSE
3278 NULL
3279 END AS [session_id],
3280 CASE waits.r
3281 WHEN 1 THEN
3282 waits.request_id
3283 ELSE
3284 NULL
3285 END AS [request_id],
3286 CASE waits.r
3287 WHEN 1 THEN
3288 waits.physical_io
3289 ELSE
3290 NULL
3291 END AS [physical_io],
3292 CASE waits.r
3293 WHEN 1 THEN
3294 waits.context_switches
3295 ELSE
3296 NULL
3297 END AS [context_switches],
3298 CASE waits.r
3299 WHEN 1 THEN
3300 waits.thread_CPU_snapshot
3301 ELSE
3302 NULL
3303 END AS [thread_CPU_snapshot],
3304 CASE waits.r
3305 WHEN 1 THEN
3306 waits.tasks
3307 ELSE
3308 NULL
3309 END AS [tasks],
3310 CASE waits.r
3311 WHEN 1 THEN
3312 waits.block_info
3313 ELSE
3314 NULL
3315 END AS [block_info],
3316 REPLACE
3317 (
3318 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
3319 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
3320 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
3321 CONVERT
3322 (
3323 NVARCHAR(MAX),
3324 N''('' +
3325 CONVERT(NVARCHAR, num_waits) + N''x: '' +
3326 CASE num_waits
3327 WHEN 1 THEN
3328 CONVERT(NVARCHAR, min_wait_time) + N''ms''
3329 WHEN 2 THEN
3330 CASE
3331 WHEN min_wait_time <> max_wait_time THEN
3332 CONVERT(NVARCHAR, min_wait_time) + N''/'' + CONVERT(NVARCHAR, max_wait_time) + N''ms''
3333 ELSE
3334 CONVERT(NVARCHAR, max_wait_time) + N''ms''
3335 END
3336 ELSE
3337 CASE
3338 WHEN min_wait_time <> max_wait_time THEN
3339 CONVERT(NVARCHAR, min_wait_time) + N''/'' + CONVERT(NVARCHAR, avg_wait_time) + N''/'' + CONVERT(NVARCHAR, max_wait_time) + N''ms''
3340 ELSE
3341 CONVERT(NVARCHAR, max_wait_time) + N''ms''
3342 END
3343 END +
3344 N'')'' + wait_type COLLATE Latin1_General_Bin2
3345 ),
3346 NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''),
3347 NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''),
3348 NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''),
3349 NCHAR(0),
3350 N''''
3351 ) AS [waits]
3352 FROM
3353 (
3354 SELECT TOP(@i)
3355 w1.*,
3356 ROW_NUMBER() OVER
3357 (
3358 PARTITION BY
3359 w1.session_id,
3360 w1.request_id
3361 ORDER BY
3362 w1.block_info DESC,
3363 w1.num_waits DESC,
3364 w1.wait_type
3365 ) AS r
3366 FROM
3367 (
3368 SELECT TOP(@i)
3369 task_info.session_id,
3370 task_info.request_id,
3371 task_info.physical_io,
3372 task_info.context_switches,
3373 task_info.thread_CPU_snapshot,
3374 task_info.num_tasks AS tasks,
3375 CASE
3376 WHEN task_info.runnable_time IS NOT NULL THEN
3377 ''RUNNABLE''
3378 ELSE
3379 wt2.wait_type
3380 END AS wait_type,
3381 NULLIF(COUNT(COALESCE(task_info.runnable_time, wt2.waiting_task_address)), 0) AS num_waits,
3382 MIN(COALESCE(task_info.runnable_time, wt2.wait_duration_ms)) AS min_wait_time,
3383 AVG(COALESCE(task_info.runnable_time, wt2.wait_duration_ms)) AS avg_wait_time,
3384 MAX(COALESCE(task_info.runnable_time, wt2.wait_duration_ms)) AS max_wait_time,
3385 MAX(wt2.block_info) AS block_info
3386 FROM
3387 (
3388 SELECT TOP(@i)
3389 t.session_id,
3390 t.request_id,
3391 SUM(CONVERT(BIGINT, t.pending_io_count)) OVER (PARTITION BY t.session_id, t.request_id) AS physical_io,
3392 SUM(CONVERT(BIGINT, t.context_switches_count)) OVER (PARTITION BY t.session_id, t.request_id) AS context_switches,
3393 ' +
3394 CASE
3395 WHEN @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|'
3396 THEN
3397 'SUM(tr.usermode_time + tr.kernel_time) OVER (PARTITION BY t.session_id, t.request_id) '
3398 ELSE
3399 'CONVERT(BIGINT, NULL) '
3400 END +
3401 ' AS thread_CPU_snapshot,
3402 COUNT(*) OVER (PARTITION BY t.session_id, t.request_id) AS num_tasks,
3403 t.task_address,
3404 t.task_state,
3405 CASE
3406 WHEN
3407 t.task_state = ''RUNNABLE''
3408 AND w.runnable_time > 0 THEN
3409 w.runnable_time
3410 ELSE
3411 NULL
3412 END AS runnable_time
3413 FROM sys.dm_os_tasks AS t
3414 CROSS APPLY
3415 (
3416 SELECT TOP(1)
3417 sp2.session_id
3418 FROM @sessions AS sp2
3419 WHERE
3420 sp2.session_id = t.session_id
3421 AND sp2.request_id = t.request_id
3422 AND sp2.status <> ''sleeping''
3423 ) AS sp20
3424 LEFT OUTER HASH JOIN
3425 (
3426 SELECT TOP(@i)
3427 (
3428 SELECT TOP(@i)
3429 ms_ticks
3430 FROM sys.dm_os_sys_info
3431 ) -
3432 w0.wait_resumed_ms_ticks AS runnable_time,
3433 w0.worker_address,
3434 w0.thread_address,
3435 w0.task_bound_ms_ticks
3436 FROM sys.dm_os_workers AS w0
3437 WHERE
3438 w0.state = ''RUNNABLE''
3439 OR @first_collection_ms_ticks >= w0.task_bound_ms_ticks
3440 ) AS w ON
3441 w.worker_address = t.worker_address
3442 ' +
3443 CASE
3444 WHEN @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|'
3445 THEN
3446 'LEFT OUTER HASH JOIN sys.dm_os_threads AS tr ON
3447 tr.thread_address = w.thread_address
3448 AND @first_collection_ms_ticks >= w.task_bound_ms_ticks
3449 '
3450 ELSE
3451 ''
3452 END +
3453 ') AS task_info
3454 LEFT OUTER HASH JOIN
3455 (
3456 SELECT TOP(@i)
3457 wt1.wait_type,
3458 wt1.waiting_task_address,
3459 MAX(wt1.wait_duration_ms) AS wait_duration_ms,
3460 MAX(wt1.block_info) AS block_info
3461 FROM
3462 (
3463 SELECT DISTINCT TOP(@i)
3464 wt.wait_type +
3465 CASE
3466 WHEN wt.wait_type LIKE N''PAGE%LATCH_%'' THEN
3467 '':'' +
3468 COALESCE(DB_NAME(CONVERT(INT, LEFT(wt.resource_description, CHARINDEX(N'':'', wt.resource_description) - 1))), N''(null)'') +
3469 N'':'' +
3470 SUBSTRING(wt.resource_description, CHARINDEX(N'':'', wt.resource_description) + 1, LEN(wt.resource_description) - CHARINDEX(N'':'', REVERSE(wt.resource_description)) - CHARINDEX(N'':'', wt.resource_description)) +
3471 N''('' +
3472 CASE
3473 WHEN
3474 CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 1 OR
3475 CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) % 8088 = 0
3476 THEN
3477 N''PFS''
3478 WHEN
3479 CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 2 OR
3480 CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) % 511232 = 0
3481 THEN
3482 N''GAM''
3483 WHEN
3484 CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 3 OR
3485 CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) % 511233 = 0
3486 THEN
3487 N''SGAM''
3488 WHEN
3489 CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 6 OR
3490 CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) % 511238 = 0
3491 THEN
3492 N''DCM''
3493 WHEN
3494 CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 7 OR
3495 CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) % 511239 = 0
3496 THEN
3497 N''BCM''
3498 ELSE
3499 N''*''
3500 END +
3501 N'')''
3502 WHEN wt.wait_type = N''CXPACKET'' THEN
3503 N'':'' + SUBSTRING(wt.resource_description, CHARINDEX(N''nodeId'', wt.resource_description) + 7, 4)
3504 WHEN wt.wait_type LIKE N''LATCH[_]%'' THEN
3505 N'' ['' + LEFT(wt.resource_description, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description), 0), LEN(wt.resource_description) + 1) - 1) + N'']''
3506 ELSE
3507 N''''
3508 END COLLATE Latin1_General_Bin2 AS wait_type,
3509 CASE
3510 WHEN
3511 (
3512 wt.blocking_session_id IS NOT NULL
3513 AND wt.wait_type LIKE N''LCK[_]%''
3514 ) THEN
3515 (
3516 SELECT TOP(@i)
3517 x.lock_type,
3518 REPLACE
3519 (
3520 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
3521 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
3522 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
3523 DB_NAME
3524 (
3525 CONVERT
3526 (
3527 INT,
3528 SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''dbid='', wt.resource_description), 0) + 5, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''dbid='', wt.resource_description) + 5), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''dbid='', wt.resource_description) - 5)
3529 )
3530 ),
3531 NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''),
3532 NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''),
3533 NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''),
3534 NCHAR(0),
3535 N''''
3536 ) AS database_name,
3537 CASE x.lock_type
3538 WHEN N''objectlock'' THEN
3539 SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''objid='', wt.resource_description), 0) + 6, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''objid='', wt.resource_description) + 6), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''objid='', wt.resource_description) - 6)
3540 ELSE
3541 NULL
3542 END AS object_id,
3543 CASE x.lock_type
3544 WHEN N''filelock'' THEN
3545 SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''fileid='', wt.resource_description), 0) + 7, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''fileid='', wt.resource_description) + 7), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''fileid='', wt.resource_description) - 7)
3546 ELSE
3547 NULL
3548 END AS file_id,
3549 CASE
3550 WHEN x.lock_type in (N''pagelock'', N''extentlock'', N''ridlock'') THEN
3551 SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''associatedObjectId='', wt.resource_description), 0) + 19, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''associatedObjectId='', wt.resource_description) + 19), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''associatedObjectId='', wt.resource_description) - 19)
3552 WHEN x.lock_type in (N''keylock'', N''hobtlock'', N''allocunitlock'') THEN
3553 SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''hobtid='', wt.resource_description), 0) + 7, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''hobtid='', wt.resource_description) + 7), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''hobtid='', wt.resource_description) - 7)
3554 ELSE
3555 NULL
3556 END AS hobt_id,
3557 CASE x.lock_type
3558 WHEN N''applicationlock'' THEN
3559 SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''hash='', wt.resource_description), 0) + 5, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''hash='', wt.resource_description) + 5), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''hash='', wt.resource_description) - 5)
3560 ELSE
3561 NULL
3562 END AS applock_hash,
3563 CASE x.lock_type
3564 WHEN N''metadatalock'' THEN
3565 SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''subresource='', wt.resource_description), 0) + 12, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''subresource='', wt.resource_description) + 12), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''subresource='', wt.resource_description) - 12)
3566 ELSE
3567 NULL
3568 END AS metadata_resource,
3569 CASE x.lock_type
3570 WHEN N''metadatalock'' THEN
3571 SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''classid='', wt.resource_description), 0) + 8, COALESCE(NULLIF(CHARINDEX(N'' dbid='', wt.resource_description) - CHARINDEX(N''classid='', wt.resource_description), 0), LEN(wt.resource_description) + 1) - 8)
3572 ELSE
3573 NULL
3574 END AS metadata_class_id
3575 FROM
3576 (
3577 SELECT TOP(1)
3578 LEFT(wt.resource_description, CHARINDEX(N'' '', wt.resource_description) - 1) COLLATE Latin1_General_Bin2 AS lock_type
3579 ) AS x
3580 FOR XML
3581 PATH('''')
3582 )
3583 ELSE NULL
3584 END AS block_info,
3585 wt.wait_duration_ms,
3586 wt.waiting_task_address
3587 FROM
3588 (
3589 SELECT TOP(@i)
3590 wt0.wait_type COLLATE Latin1_General_Bin2 AS wait_type,
3591 wt0.resource_description COLLATE Latin1_General_Bin2 AS resource_description,
3592 wt0.wait_duration_ms,
3593 wt0.waiting_task_address,
3594 CASE
3595 WHEN wt0.blocking_session_id = p.blocked THEN
3596 wt0.blocking_session_id
3597 ELSE
3598 NULL
3599 END AS blocking_session_id
3600 FROM sys.dm_os_waiting_tasks AS wt0
3601 CROSS APPLY
3602 (
3603 SELECT TOP(1)
3604 s0.blocked
3605 FROM @sessions AS s0
3606 WHERE
3607 s0.session_id = wt0.session_id
3608 AND COALESCE(s0.wait_type, N'''') <> N''OLEDB''
3609 AND wt0.wait_type <> N''OLEDB''
3610 ) AS p
3611 ) AS wt
3612 ) AS wt1
3613 GROUP BY
3614 wt1.wait_type,
3615 wt1.waiting_task_address
3616 ) AS wt2 ON
3617 wt2.waiting_task_address = task_info.task_address
3618 AND wt2.wait_duration_ms > 0
3619 AND task_info.runnable_time IS NULL
3620 GROUP BY
3621 task_info.session_id,
3622 task_info.request_id,
3623 task_info.physical_io,
3624 task_info.context_switches,
3625 task_info.thread_CPU_snapshot,
3626 task_info.num_tasks,
3627 CASE
3628 WHEN task_info.runnable_time IS NOT NULL THEN
3629 ''RUNNABLE''
3630 ELSE
3631 wt2.wait_type
3632 END
3633 ) AS w1
3634 ) AS waits
3635 ORDER BY
3636 waits.session_id,
3637 waits.request_id,
3638 waits.r
3639 FOR XML
3640 PATH(N''tasks''),
3641 TYPE
3642 ) AS tasks_raw (task_xml_raw)
3643 ) AS tasks_final
3644 CROSS APPLY tasks_final.task_xml.nodes(N''/tasks'') AS task_nodes (task_node)
3645 WHERE
3646 task_nodes.task_node.exist(N''session_id'') = 1
3647 ) AS tasks ON
3648 tasks.session_id = y.session_id
3649 AND tasks.request_id = y.request_id
3650 '
3651 ELSE
3652 ''
3653 END +
3654 'LEFT OUTER HASH JOIN
3655 (
3656 SELECT TOP(@i)
3657 t_info.session_id,
3658 COALESCE(t_info.request_id, -1) AS request_id,
3659 SUM(t_info.tempdb_allocations) AS tempdb_allocations,
3660 SUM(t_info.tempdb_current) AS tempdb_current
3661 FROM
3662 (
3663 SELECT TOP(@i)
3664 tsu.session_id,
3665 tsu.request_id,
3666 tsu.user_objects_alloc_page_count +
3667 tsu.internal_objects_alloc_page_count AS tempdb_allocations,
3668 tsu.user_objects_alloc_page_count +
3669 tsu.internal_objects_alloc_page_count -
3670 tsu.user_objects_dealloc_page_count -
3671 tsu.internal_objects_dealloc_page_count AS tempdb_current
3672 FROM sys.dm_db_task_space_usage AS tsu
3673 CROSS APPLY
3674 (
3675 SELECT TOP(1)
3676 s0.session_id
3677 FROM @sessions AS s0
3678 WHERE
3679 s0.session_id = tsu.session_id
3680 ) AS p
3681
3682 UNION ALL
3683
3684 SELECT TOP(@i)
3685 ssu.session_id,
3686 NULL AS request_id,
3687 ssu.user_objects_alloc_page_count +
3688 ssu.internal_objects_alloc_page_count AS tempdb_allocations,
3689 ssu.user_objects_alloc_page_count +
3690 ssu.internal_objects_alloc_page_count -
3691 ssu.user_objects_dealloc_page_count -
3692 ssu.internal_objects_dealloc_page_count AS tempdb_current
3693 FROM sys.dm_db_session_space_usage AS ssu
3694 CROSS APPLY
3695 (
3696 SELECT TOP(1)
3697 s0.session_id
3698 FROM @sessions AS s0
3699 WHERE
3700 s0.session_id = ssu.session_id
3701 ) AS p
3702 ) AS t_info
3703 GROUP BY
3704 t_info.session_id,
3705 COALESCE(t_info.request_id, -1)
3706 ) AS tempdb_info ON
3707 tempdb_info.session_id = y.session_id
3708 AND tempdb_info.request_id =
3709 CASE
3710 WHEN y.status = N''sleeping'' THEN
3711 -1
3712 ELSE
3713 y.request_id
3714 END
3715 ' +
3716 CASE
3717 WHEN
3718 NOT
3719 (
3720 @get_avg_time = 1
3721 AND @recursion = 1
3722 ) THEN
3723 ''
3724 ELSE
3725 'LEFT OUTER HASH JOIN
3726 (
3727 SELECT TOP(@i)
3728 *
3729 FROM sys.dm_exec_query_stats
3730 ) AS qs ON
3731 qs.sql_handle = y.sql_handle
3732 AND qs.plan_handle = y.plan_handle
3733 AND qs.statement_start_offset = y.statement_start_offset
3734 AND qs.statement_end_offset = y.statement_end_offset
3735 '
3736 END +
3737 ') AS x
3738 OPTION (KEEPFIXED PLAN, OPTIMIZE FOR (@i = 1)); ';
3739
3740 SET @sql_n = CONVERT(NVARCHAR(MAX), @sql);
3741
3742 SET @last_collection_start = GETDATE();
3743
3744 IF @recursion = -1
3745 BEGIN;
3746 SELECT
3747 @first_collection_ms_ticks = ms_ticks
3748 FROM sys.dm_os_sys_info;
3749 END;
3750
3751 INSERT #sessions
3752 (
3753 recursion,
3754 session_id,
3755 request_id,
3756 session_number,
3757 elapsed_time,
3758 avg_elapsed_time,
3759 physical_io,
3760 reads,
3761 physical_reads,
3762 writes,
3763 tempdb_allocations,
3764 tempdb_current,
3765 CPU,
3766 thread_CPU_snapshot,
3767 context_switches,
3768 used_memory,
3769 tasks,
3770 status,
3771 wait_info,
3772 transaction_id,
3773 open_tran_count,
3774 sql_handle,
3775 statement_start_offset,
3776 statement_end_offset,
3777 sql_text,
3778 plan_handle,
3779 blocking_session_id,
3780 percent_complete,
3781 host_name,
3782 login_name,
3783 database_name,
3784 program_name,
3785 additional_info,
3786 start_time,
3787 login_time,
3788 last_request_start_time
3789 )
3790 EXEC sp_executesql
3791 @sql_n,
3792 N'@recursion SMALLINT, @filter sysname, @not_filter sysname, @first_collection_ms_ticks BIGINT',
3793 @recursion, @filter, @not_filter, @first_collection_ms_ticks;
3794
3795 --Collect transaction information?
3796 IF
3797 @recursion = 1
3798 AND
3799 (
3800 @output_column_list LIKE '%|[tran_start_time|]%' ESCAPE '|'
3801 OR @output_column_list LIKE '%|[tran_log_writes|]%' ESCAPE '|'
3802 )
3803 BEGIN;
3804 DECLARE @i INT;
3805 SET @i = 2147483647;
3806
3807 UPDATE s
3808 SET
3809 tran_start_time =
3810 CONVERT
3811 (
3812 DATETIME,
3813 LEFT
3814 (
3815 x.trans_info,
3816 NULLIF(CHARINDEX(NCHAR(254) COLLATE Latin1_General_Bin2, x.trans_info) - 1, -1)
3817 ),
3818 121
3819 ),
3820 tran_log_writes =
3821 RIGHT
3822 (
3823 x.trans_info,
3824 LEN(x.trans_info) - CHARINDEX(NCHAR(254) COLLATE Latin1_General_Bin2, x.trans_info)
3825 )
3826 FROM
3827 (
3828 SELECT TOP(@i)
3829 trans_nodes.trans_node.value('(session_id/text())[1]', 'SMALLINT') AS session_id,
3830 COALESCE(trans_nodes.trans_node.value('(request_id/text())[1]', 'INT'), 0) AS request_id,
3831 trans_nodes.trans_node.value('(trans_info/text())[1]', 'NVARCHAR(4000)') AS trans_info
3832 FROM
3833 (
3834 SELECT TOP(@i)
3835 CONVERT
3836 (
3837 XML,
3838 REPLACE
3839 (
3840 CONVERT(NVARCHAR(MAX), trans_raw.trans_xml_raw) COLLATE Latin1_General_Bin2,
3841 N'</trans_info></trans><trans><trans_info>', N''
3842 )
3843 )
3844 FROM
3845 (
3846 SELECT TOP(@i)
3847 CASE u_trans.r
3848 WHEN 1 THEN u_trans.session_id
3849 ELSE NULL
3850 END AS [session_id],
3851 CASE u_trans.r
3852 WHEN 1 THEN u_trans.request_id
3853 ELSE NULL
3854 END AS [request_id],
3855 CONVERT
3856 (
3857 NVARCHAR(MAX),
3858 CASE
3859 WHEN u_trans.database_id IS NOT NULL THEN
3860 CASE u_trans.r
3861 WHEN 1 THEN COALESCE(CONVERT(NVARCHAR, u_trans.transaction_start_time, 121) + NCHAR(254), N'')
3862 ELSE N''
3863 END +
3864 REPLACE
3865 (
3866 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
3867 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
3868 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
3869 CONVERT(VARCHAR(128), COALESCE(DB_NAME(u_trans.database_id), N'(null)')),
3870 NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'),
3871 NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'),
3872 NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'),
3873 NCHAR(0),
3874 N'?'
3875 ) +
3876 N': ' +
3877 CONVERT(NVARCHAR, u_trans.log_record_count) + N' (' + CONVERT(NVARCHAR, u_trans.log_kb_used) + N' kB)' +
3878 N','
3879 ELSE
3880 N'N/A,'
3881 END COLLATE Latin1_General_Bin2
3882 ) AS [trans_info]
3883 FROM
3884 (
3885 SELECT TOP(@i)
3886 trans.*,
3887 ROW_NUMBER() OVER
3888 (
3889 PARTITION BY
3890 trans.session_id,
3891 trans.request_id
3892 ORDER BY
3893 trans.transaction_start_time DESC
3894 ) AS r
3895 FROM
3896 (
3897 SELECT TOP(@i)
3898 session_tran_map.session_id,
3899 session_tran_map.request_id,
3900 s_tran.database_id,
3901 COALESCE(SUM(s_tran.database_transaction_log_record_count), 0) AS log_record_count,
3902 COALESCE(SUM(s_tran.database_transaction_log_bytes_used), 0) / 1024 AS log_kb_used,
3903 MIN(s_tran.database_transaction_begin_time) AS transaction_start_time
3904 FROM
3905 (
3906 SELECT TOP(@i)
3907 *
3908 FROM sys.dm_tran_active_transactions
3909 WHERE
3910 transaction_begin_time <= @last_collection_start
3911 ) AS a_tran
3912 INNER HASH JOIN
3913 (
3914 SELECT TOP(@i)
3915 *
3916 FROM sys.dm_tran_database_transactions
3917 WHERE
3918 database_id < 32767
3919 ) AS s_tran ON
3920 s_tran.transaction_id = a_tran.transaction_id
3921 LEFT OUTER HASH JOIN
3922 (
3923 SELECT TOP(@i)
3924 *
3925 FROM sys.dm_tran_session_transactions
3926 ) AS tst ON
3927 s_tran.transaction_id = tst.transaction_id
3928 CROSS APPLY
3929 (
3930 SELECT TOP(1)
3931 s3.session_id,
3932 s3.request_id
3933 FROM
3934 (
3935 SELECT TOP(1)
3936 s1.session_id,
3937 s1.request_id
3938 FROM #sessions AS s1
3939 WHERE
3940 s1.transaction_id = s_tran.transaction_id
3941 AND s1.recursion = 1
3942
3943 UNION ALL
3944
3945 SELECT TOP(1)
3946 s2.session_id,
3947 s2.request_id
3948 FROM #sessions AS s2
3949 WHERE
3950 s2.session_id = tst.session_id
3951 AND s2.recursion = 1
3952 ) AS s3
3953 ORDER BY
3954 s3.request_id
3955 ) AS session_tran_map
3956 GROUP BY
3957 session_tran_map.session_id,
3958 session_tran_map.request_id,
3959 s_tran.database_id
3960 ) AS trans
3961 ) AS u_trans
3962 FOR XML
3963 PATH('trans'),
3964 TYPE
3965 ) AS trans_raw (trans_xml_raw)
3966 ) AS trans_final (trans_xml)
3967 CROSS APPLY trans_final.trans_xml.nodes('/trans') AS trans_nodes (trans_node)
3968 ) AS x
3969 INNER HASH JOIN #sessions AS s ON
3970 s.session_id = x.session_id
3971 AND s.request_id = x.request_id
3972 OPTION (OPTIMIZE FOR (@i = 1));
3973 END;
3974
3975 --Variables for text and plan collection
3976 DECLARE
3977 @session_id SMALLINT,
3978 @request_id INT,
3979 @sql_handle VARBINARY(64),
3980 @plan_handle VARBINARY(64),
3981 @statement_start_offset INT,
3982 @statement_end_offset INT,
3983 @start_time DATETIME,
3984 @database_name sysname;
3985
3986 IF
3987 @recursion = 1
3988 AND @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|'
3989 BEGIN;
3990 DECLARE sql_cursor
3991 CURSOR LOCAL FAST_FORWARD
3992 FOR
3993 SELECT
3994 session_id,
3995 request_id,
3996 sql_handle,
3997 statement_start_offset,
3998 statement_end_offset
3999 FROM #sessions
4000 WHERE
4001 recursion = 1
4002 AND sql_handle IS NOT NULL
4003 OPTION (KEEPFIXED PLAN);
4004
4005 OPEN sql_cursor;
4006
4007 FETCH NEXT FROM sql_cursor
4008 INTO
4009 @session_id,
4010 @request_id,
4011 @sql_handle,
4012 @statement_start_offset,
4013 @statement_end_offset;
4014
4015 --Wait up to 5 ms for the SQL text, then give up
4016 SET LOCK_TIMEOUT 5;
4017
4018 WHILE @@FETCH_STATUS = 0
4019 BEGIN;
4020 BEGIN TRY;
4021 UPDATE s
4022 SET
4023 s.sql_text =
4024 (
4025 SELECT
4026 REPLACE
4027 (
4028 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4029 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4030 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4031 N'--' + NCHAR(13) + NCHAR(10) +
4032 CASE
4033 WHEN @get_full_inner_text = 1 THEN est.text
4034 WHEN LEN(est.text) < (@statement_end_offset / 2) + 1 THEN est.text
4035 WHEN SUBSTRING(est.text, (@statement_start_offset/2), 2) LIKE N'[a-zA-Z0-9][a-zA-Z0-9]' THEN est.text
4036 ELSE
4037 CASE
4038 WHEN @statement_start_offset > 0 THEN
4039 SUBSTRING
4040 (
4041 est.text,
4042 ((@statement_start_offset/2) + 1),
4043 (
4044 CASE
4045 WHEN @statement_end_offset = -1 THEN 2147483647
4046 ELSE ((@statement_end_offset - @statement_start_offset)/2) + 1
4047 END
4048 )
4049 )
4050 ELSE RTRIM(LTRIM(est.text))
4051 END
4052 END +
4053 NCHAR(13) + NCHAR(10) + N'--' COLLATE Latin1_General_Bin2,
4054 NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'),
4055 NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'),
4056 NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'),
4057 NCHAR(0),
4058 N''
4059 ) AS [processing-instruction(query)]
4060 FOR XML
4061 PATH(''),
4062 TYPE
4063 ),
4064 s.statement_start_offset =
4065 CASE
4066 WHEN LEN(est.text) < (@statement_end_offset / 2) + 1 THEN 0
4067 WHEN SUBSTRING(CONVERT(VARCHAR(MAX), est.text), (@statement_start_offset/2), 2) LIKE '[a-zA-Z0-9][a-zA-Z0-9]' THEN 0
4068 ELSE @statement_start_offset
4069 END,
4070 s.statement_end_offset =
4071 CASE
4072 WHEN LEN(est.text) < (@statement_end_offset / 2) + 1 THEN -1
4073 WHEN SUBSTRING(CONVERT(VARCHAR(MAX), est.text), (@statement_start_offset/2), 2) LIKE '[a-zA-Z0-9][a-zA-Z0-9]' THEN -1
4074 ELSE @statement_end_offset
4075 END
4076 FROM
4077 #sessions AS s,
4078 (
4079 SELECT TOP(1)
4080 text
4081 FROM
4082 (
4083 SELECT
4084 text,
4085 0 AS row_num
4086 FROM sys.dm_exec_sql_text(@sql_handle)
4087
4088 UNION ALL
4089
4090 SELECT
4091 NULL,
4092 1 AS row_num
4093 ) AS est0
4094 ORDER BY
4095 row_num
4096 ) AS est
4097 WHERE
4098 s.session_id = @session_id
4099 AND s.request_id = @request_id
4100 AND s.recursion = 1
4101 OPTION (KEEPFIXED PLAN);
4102 END TRY
4103 BEGIN CATCH;
4104 UPDATE s
4105 SET
4106 s.sql_text =
4107 CASE ERROR_NUMBER()
4108 WHEN 1222 THEN '<timeout_exceeded />'
4109 ELSE '<error message="' + ERROR_MESSAGE() + '" />'
4110 END
4111 FROM #sessions AS s
4112 WHERE
4113 s.session_id = @session_id
4114 AND s.request_id = @request_id
4115 AND s.recursion = 1
4116 OPTION (KEEPFIXED PLAN);
4117 END CATCH;
4118
4119 FETCH NEXT FROM sql_cursor
4120 INTO
4121 @session_id,
4122 @request_id,
4123 @sql_handle,
4124 @statement_start_offset,
4125 @statement_end_offset;
4126 END;
4127
4128 --Return this to the default
4129 SET LOCK_TIMEOUT -1;
4130
4131 CLOSE sql_cursor;
4132 DEALLOCATE sql_cursor;
4133 END;
4134
4135 IF
4136 @get_outer_command = 1
4137 AND @recursion = 1
4138 AND @output_column_list LIKE '%|[sql_command|]%' ESCAPE '|'
4139 BEGIN;
4140 DECLARE @buffer_results TABLE
4141 (
4142 EventType VARCHAR(30),
4143 Parameters INT,
4144 EventInfo NVARCHAR(4000),
4145 start_time DATETIME,
4146 session_number INT IDENTITY(1,1) NOT NULL PRIMARY KEY
4147 );
4148
4149 DECLARE buffer_cursor
4150 CURSOR LOCAL FAST_FORWARD
4151 FOR
4152 SELECT
4153 session_id,
4154 MAX(start_time) AS start_time
4155 FROM #sessions
4156 WHERE
4157 recursion = 1
4158 GROUP BY
4159 session_id
4160 ORDER BY
4161 session_id
4162 OPTION (KEEPFIXED PLAN);
4163
4164 OPEN buffer_cursor;
4165
4166 FETCH NEXT FROM buffer_cursor
4167 INTO
4168 @session_id,
4169 @start_time;
4170
4171 WHILE @@FETCH_STATUS = 0
4172 BEGIN;
4173 BEGIN TRY;
4174 --In SQL Server 2008, DBCC INPUTBUFFER will throw
4175 --an exception if the session no longer exists
4176 INSERT @buffer_results
4177 (
4178 EventType,
4179 Parameters,
4180 EventInfo
4181 )
4182 EXEC sp_executesql
4183 N'DBCC INPUTBUFFER(@session_id) WITH NO_INFOMSGS;',
4184 N'@session_id SMALLINT',
4185 @session_id;
4186
4187 UPDATE br
4188 SET
4189 br.start_time = @start_time
4190 FROM @buffer_results AS br
4191 WHERE
4192 br.session_number =
4193 (
4194 SELECT MAX(br2.session_number)
4195 FROM @buffer_results br2
4196 );
4197 END TRY
4198 BEGIN CATCH
4199 END CATCH;
4200
4201 FETCH NEXT FROM buffer_cursor
4202 INTO
4203 @session_id,
4204 @start_time;
4205 END;
4206
4207 UPDATE s
4208 SET
4209 sql_command =
4210 (
4211 SELECT
4212 REPLACE
4213 (
4214 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4215 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4216 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4217 CONVERT
4218 (
4219 NVARCHAR(MAX),
4220 N'--' + NCHAR(13) + NCHAR(10) + br.EventInfo + NCHAR(13) + NCHAR(10) + N'--' COLLATE Latin1_General_Bin2
4221 ),
4222 NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'),
4223 NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'),
4224 NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'),
4225 NCHAR(0),
4226 N''
4227 ) AS [processing-instruction(query)]
4228 FROM @buffer_results AS br
4229 WHERE
4230 br.session_number = s.session_number
4231 AND br.start_time = s.start_time
4232 AND
4233 (
4234 (
4235 s.start_time = s.last_request_start_time
4236 AND EXISTS
4237 (
4238 SELECT *
4239 FROM sys.dm_exec_requests r2
4240 WHERE
4241 r2.session_id = s.session_id
4242 AND r2.request_id = s.request_id
4243 AND r2.start_time = s.start_time
4244 )
4245 )
4246 OR
4247 (
4248 s.request_id = 0
4249 AND EXISTS
4250 (
4251 SELECT *
4252 FROM sys.dm_exec_sessions s2
4253 WHERE
4254 s2.session_id = s.session_id
4255 AND s2.last_request_start_time = s.last_request_start_time
4256 )
4257 )
4258 )
4259 FOR XML
4260 PATH(''),
4261 TYPE
4262 )
4263 FROM #sessions AS s
4264 WHERE
4265 recursion = 1
4266 OPTION (KEEPFIXED PLAN);
4267
4268 CLOSE buffer_cursor;
4269 DEALLOCATE buffer_cursor;
4270 END;
4271
4272 IF
4273 @get_plans >= 1
4274 AND @recursion = 1
4275 AND @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|'
4276 BEGIN;
4277 DECLARE plan_cursor
4278 CURSOR LOCAL FAST_FORWARD
4279 FOR
4280 SELECT
4281 session_id,
4282 request_id,
4283 plan_handle,
4284 statement_start_offset,
4285 statement_end_offset
4286 FROM #sessions
4287 WHERE
4288 recursion = 1
4289 AND plan_handle IS NOT NULL
4290 OPTION (KEEPFIXED PLAN);
4291
4292 OPEN plan_cursor;
4293
4294 FETCH NEXT FROM plan_cursor
4295 INTO
4296 @session_id,
4297 @request_id,
4298 @plan_handle,
4299 @statement_start_offset,
4300 @statement_end_offset;
4301
4302 --Wait up to 5 ms for a query plan, then give up
4303 SET LOCK_TIMEOUT 5;
4304
4305 WHILE @@FETCH_STATUS = 0
4306 BEGIN;
4307 BEGIN TRY;
4308 UPDATE s
4309 SET
4310 s.query_plan =
4311 (
4312 SELECT
4313 CONVERT(xml, query_plan)
4314 FROM sys.dm_exec_text_query_plan
4315 (
4316 @plan_handle,
4317 CASE @get_plans
4318 WHEN 1 THEN
4319 @statement_start_offset
4320 ELSE
4321 0
4322 END,
4323 CASE @get_plans
4324 WHEN 1 THEN
4325 @statement_end_offset
4326 ELSE
4327 -1
4328 END
4329 )
4330 )
4331 FROM #sessions AS s
4332 WHERE
4333 s.session_id = @session_id
4334 AND s.request_id = @request_id
4335 AND s.recursion = 1
4336 OPTION (KEEPFIXED PLAN);
4337 END TRY
4338 BEGIN CATCH;
4339 IF ERROR_NUMBER() = 6335
4340 BEGIN;
4341 UPDATE s
4342 SET
4343 s.query_plan =
4344 (
4345 SELECT
4346 N'--' + NCHAR(13) + NCHAR(10) +
4347 N'-- Could not render showplan due to XML data type limitations. ' + NCHAR(13) + NCHAR(10) +
4348 N'-- To see the graphical plan save the XML below as a .SQLPLAN file and re-open in SSMS.' + NCHAR(13) + NCHAR(10) +
4349 N'--' + NCHAR(13) + NCHAR(10) +
4350 REPLACE(qp.query_plan, N'<RelOp', NCHAR(13)+NCHAR(10)+N'<RelOp') +
4351 NCHAR(13) + NCHAR(10) + N'--' COLLATE Latin1_General_Bin2 AS [processing-instruction(query_plan)]
4352 FROM sys.dm_exec_text_query_plan
4353 (
4354 @plan_handle,
4355 CASE @get_plans
4356 WHEN 1 THEN
4357 @statement_start_offset
4358 ELSE
4359 0
4360 END,
4361 CASE @get_plans
4362 WHEN 1 THEN
4363 @statement_end_offset
4364 ELSE
4365 -1
4366 END
4367 ) AS qp
4368 FOR XML
4369 PATH(''),
4370 TYPE
4371 )
4372 FROM #sessions AS s
4373 WHERE
4374 s.session_id = @session_id
4375 AND s.request_id = @request_id
4376 AND s.recursion = 1
4377 OPTION (KEEPFIXED PLAN);
4378 END;
4379 ELSE
4380 BEGIN;
4381 UPDATE s
4382 SET
4383 s.query_plan =
4384 CASE ERROR_NUMBER()
4385 WHEN 1222 THEN '<timeout_exceeded />'
4386 ELSE '<error message="' + ERROR_MESSAGE() + '" />'
4387 END
4388 FROM #sessions AS s
4389 WHERE
4390 s.session_id = @session_id
4391 AND s.request_id = @request_id
4392 AND s.recursion = 1
4393 OPTION (KEEPFIXED PLAN);
4394 END;
4395 END CATCH;
4396
4397 FETCH NEXT FROM plan_cursor
4398 INTO
4399 @session_id,
4400 @request_id,
4401 @plan_handle,
4402 @statement_start_offset,
4403 @statement_end_offset;
4404 END;
4405
4406 --Return this to the default
4407 SET LOCK_TIMEOUT -1;
4408
4409 CLOSE plan_cursor;
4410 DEALLOCATE plan_cursor;
4411 END;
4412
4413 IF
4414 @get_locks = 1
4415 AND @recursion = 1
4416 AND @output_column_list LIKE '%|[locks|]%' ESCAPE '|'
4417 BEGIN;
4418 DECLARE locks_cursor
4419 CURSOR LOCAL FAST_FORWARD
4420 FOR
4421 SELECT DISTINCT
4422 database_name
4423 FROM #locks
4424 WHERE
4425 EXISTS
4426 (
4427 SELECT *
4428 FROM #sessions AS s
4429 WHERE
4430 s.session_id = #locks.session_id
4431 AND recursion = 1
4432 )
4433 AND database_name <> '(null)'
4434 OPTION (KEEPFIXED PLAN);
4435
4436 OPEN locks_cursor;
4437
4438 FETCH NEXT FROM locks_cursor
4439 INTO
4440 @database_name;
4441
4442 WHILE @@FETCH_STATUS = 0
4443 BEGIN;
4444 BEGIN TRY;
4445 SET @sql_n = CONVERT(NVARCHAR(MAX), '') +
4446 'UPDATE l ' +
4447 'SET ' +
4448 'object_name = ' +
4449 'REPLACE ' +
4450 '( ' +
4451 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4452 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4453 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4454 'o.name COLLATE Latin1_General_Bin2, ' +
4455 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' +
4456 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' +
4457 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' +
4458 'NCHAR(0), ' +
4459 N''''' ' +
4460 '), ' +
4461 'index_name = ' +
4462 'REPLACE ' +
4463 '( ' +
4464 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4465 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4466 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4467 'i.name COLLATE Latin1_General_Bin2, ' +
4468 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' +
4469 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' +
4470 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' +
4471 'NCHAR(0), ' +
4472 N''''' ' +
4473 '), ' +
4474 'schema_name = ' +
4475 'REPLACE ' +
4476 '( ' +
4477 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4478 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4479 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4480 's.name COLLATE Latin1_General_Bin2, ' +
4481 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' +
4482 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' +
4483 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' +
4484 'NCHAR(0), ' +
4485 N''''' ' +
4486 '), ' +
4487 'principal_name = ' +
4488 'REPLACE ' +
4489 '( ' +
4490 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4491 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4492 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4493 'dp.name COLLATE Latin1_General_Bin2, ' +
4494 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' +
4495 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' +
4496 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' +
4497 'NCHAR(0), ' +
4498 N''''' ' +
4499 ') ' +
4500 'FROM #locks AS l ' +
4501 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.allocation_units AS au ON ' +
4502 'au.allocation_unit_id = l.allocation_unit_id ' +
4503 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.partitions AS p ON ' +
4504 'p.hobt_id = ' +
4505 'COALESCE ' +
4506 '( ' +
4507 'l.hobt_id, ' +
4508 'CASE ' +
4509 'WHEN au.type IN (1, 3) THEN au.container_id ' +
4510 'ELSE NULL ' +
4511 'END ' +
4512 ') ' +
4513 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.partitions AS p1 ON ' +
4514 'l.hobt_id IS NULL ' +
4515 'AND au.type = 2 ' +
4516 'AND p1.partition_id = au.container_id ' +
4517 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.objects AS o ON ' +
4518 'o.object_id = COALESCE(l.object_id, p.object_id, p1.object_id) ' +
4519 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.indexes AS i ON ' +
4520 'i.object_id = COALESCE(l.object_id, p.object_id, p1.object_id) ' +
4521 'AND i.index_id = COALESCE(l.index_id, p.index_id, p1.index_id) ' +
4522 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.schemas AS s ON ' +
4523 's.schema_id = COALESCE(l.schema_id, o.schema_id) ' +
4524 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.database_principals AS dp ON ' +
4525 'dp.principal_id = l.principal_id ' +
4526 'WHERE ' +
4527 'l.database_name = @database_name ' +
4528 'OPTION (KEEPFIXED PLAN); ';
4529
4530 EXEC sp_executesql
4531 @sql_n,
4532 N'@database_name sysname',
4533 @database_name;
4534 END TRY
4535 BEGIN CATCH;
4536 UPDATE #locks
4537 SET
4538 query_error =
4539 REPLACE
4540 (
4541 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4542 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4543 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4544 CONVERT
4545 (
4546 NVARCHAR(MAX),
4547 ERROR_MESSAGE() COLLATE Latin1_General_Bin2
4548 ),
4549 NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'),
4550 NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'),
4551 NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'),
4552 NCHAR(0),
4553 N''
4554 )
4555 WHERE
4556 database_name = @database_name
4557 OPTION (KEEPFIXED PLAN);
4558 END CATCH;
4559
4560 FETCH NEXT FROM locks_cursor
4561 INTO
4562 @database_name;
4563 END;
4564
4565 CLOSE locks_cursor;
4566 DEALLOCATE locks_cursor;
4567
4568 CREATE CLUSTERED INDEX IX_SRD ON #locks (session_id, request_id, database_name);
4569
4570 UPDATE s
4571 SET
4572 s.locks =
4573 (
4574 SELECT
4575 REPLACE
4576 (
4577 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4578 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4579 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4580 CONVERT
4581 (
4582 NVARCHAR(MAX),
4583 l1.database_name COLLATE Latin1_General_Bin2
4584 ),
4585 NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'),
4586 NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'),
4587 NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'),
4588 NCHAR(0),
4589 N''
4590 ) AS [Database/@name],
4591 MIN(l1.query_error) AS [Database/@query_error],
4592 (
4593 SELECT
4594 l2.request_mode AS [Lock/@request_mode],
4595 l2.request_status AS [Lock/@request_status],
4596 COUNT(*) AS [Lock/@request_count]
4597 FROM #locks AS l2
4598 WHERE
4599 l1.session_id = l2.session_id
4600 AND l1.request_id = l2.request_id
4601 AND l2.database_name = l1.database_name
4602 AND l2.resource_type = 'DATABASE'
4603 GROUP BY
4604 l2.request_mode,
4605 l2.request_status
4606 FOR XML
4607 PATH(''),
4608 TYPE
4609 ) AS [Database/Locks],
4610 (
4611 SELECT
4612 COALESCE(l3.object_name, '(null)') AS [Object/@name],
4613 l3.schema_name AS [Object/@schema_name],
4614 (
4615 SELECT
4616 l4.resource_type AS [Lock/@resource_type],
4617 l4.page_type AS [Lock/@page_type],
4618 l4.index_name AS [Lock/@index_name],
4619 CASE
4620 WHEN l4.object_name IS NULL THEN l4.schema_name
4621 ELSE NULL
4622 END AS [Lock/@schema_name],
4623 l4.principal_name AS [Lock/@principal_name],
4624 l4.resource_description AS [Lock/@resource_description],
4625 l4.request_mode AS [Lock/@request_mode],
4626 l4.request_status AS [Lock/@request_status],
4627 SUM(l4.request_count) AS [Lock/@request_count]
4628 FROM #locks AS l4
4629 WHERE
4630 l4.session_id = l3.session_id
4631 AND l4.request_id = l3.request_id
4632 AND l3.database_name = l4.database_name
4633 AND COALESCE(l3.object_name, '(null)') = COALESCE(l4.object_name, '(null)')
4634 AND COALESCE(l3.schema_name, '') = COALESCE(l4.schema_name, '')
4635 AND l4.resource_type <> 'DATABASE'
4636 GROUP BY
4637 l4.resource_type,
4638 l4.page_type,
4639 l4.index_name,
4640 CASE
4641 WHEN l4.object_name IS NULL THEN l4.schema_name
4642 ELSE NULL
4643 END,
4644 l4.principal_name,
4645 l4.resource_description,
4646 l4.request_mode,
4647 l4.request_status
4648 FOR XML
4649 PATH(''),
4650 TYPE
4651 ) AS [Object/Locks]
4652 FROM #locks AS l3
4653 WHERE
4654 l3.session_id = l1.session_id
4655 AND l3.request_id = l1.request_id
4656 AND l3.database_name = l1.database_name
4657 AND l3.resource_type <> 'DATABASE'
4658 GROUP BY
4659 l3.session_id,
4660 l3.request_id,
4661 l3.database_name,
4662 COALESCE(l3.object_name, '(null)'),
4663 l3.schema_name
4664 FOR XML
4665 PATH(''),
4666 TYPE
4667 ) AS [Database/Objects]
4668 FROM #locks AS l1
4669 WHERE
4670 l1.session_id = s.session_id
4671 AND l1.request_id = s.request_id
4672 AND l1.start_time IN (s.start_time, s.last_request_start_time)
4673 AND s.recursion = 1
4674 GROUP BY
4675 l1.session_id,
4676 l1.request_id,
4677 l1.database_name
4678 FOR XML
4679 PATH(''),
4680 TYPE
4681 )
4682 FROM #sessions s
4683 OPTION (KEEPFIXED PLAN);
4684 END;
4685
4686 IF
4687 @find_block_leaders = 1
4688 AND @recursion = 1
4689 AND @output_column_list LIKE '%|[blocked_session_count|]%' ESCAPE '|'
4690 BEGIN;
4691 WITH
4692 blockers AS
4693 (
4694 SELECT
4695 session_id,
4696 session_id AS top_level_session_id
4697 FROM #sessions
4698 WHERE
4699 recursion = 1
4700
4701 UNION ALL
4702
4703 SELECT
4704 s.session_id,
4705 b.top_level_session_id
4706 FROM blockers AS b
4707 JOIN #sessions AS s ON
4708 s.blocking_session_id = b.session_id
4709 AND s.recursion = 1
4710 )
4711 UPDATE s
4712 SET
4713 s.blocked_session_count = x.blocked_session_count
4714 FROM #sessions AS s
4715 JOIN
4716 (
4717 SELECT
4718 b.top_level_session_id AS session_id,
4719 COUNT(*) - 1 AS blocked_session_count
4720 FROM blockers AS b
4721 GROUP BY
4722 b.top_level_session_id
4723 ) x ON
4724 s.session_id = x.session_id
4725 WHERE
4726 s.recursion = 1;
4727 END;
4728
4729 IF
4730 @get_task_info = 2
4731 AND @output_column_list LIKE '%|[additional_info|]%' ESCAPE '|'
4732 AND @recursion = 1
4733 BEGIN;
4734 CREATE TABLE #blocked_requests
4735 (
4736 session_id SMALLINT NOT NULL,
4737 request_id INT NOT NULL,
4738 database_name sysname NOT NULL,
4739 object_id INT,
4740 hobt_id BIGINT,
4741 schema_id INT,
4742 schema_name sysname NULL,
4743 object_name sysname NULL,
4744 query_error NVARCHAR(2048),
4745 PRIMARY KEY (database_name, session_id, request_id)
4746 );
4747
4748 CREATE STATISTICS s_database_name ON #blocked_requests (database_name)
4749 WITH SAMPLE 0 ROWS, NORECOMPUTE;
4750 CREATE STATISTICS s_schema_name ON #blocked_requests (schema_name)
4751 WITH SAMPLE 0 ROWS, NORECOMPUTE;
4752 CREATE STATISTICS s_object_name ON #blocked_requests (object_name)
4753 WITH SAMPLE 0 ROWS, NORECOMPUTE;
4754 CREATE STATISTICS s_query_error ON #blocked_requests (query_error)
4755 WITH SAMPLE 0 ROWS, NORECOMPUTE;
4756
4757 INSERT #blocked_requests
4758 (
4759 session_id,
4760 request_id,
4761 database_name,
4762 object_id,
4763 hobt_id,
4764 schema_id
4765 )
4766 SELECT
4767 session_id,
4768 request_id,
4769 database_name,
4770 object_id,
4771 hobt_id,
4772 CONVERT(INT, SUBSTRING(schema_node, CHARINDEX(' = ', schema_node) + 3, LEN(schema_node))) AS schema_id
4773 FROM
4774 (
4775 SELECT
4776 session_id,
4777 request_id,
4778 agent_nodes.agent_node.value('(database_name/text())[1]', 'sysname') AS database_name,
4779 agent_nodes.agent_node.value('(object_id/text())[1]', 'int') AS object_id,
4780 agent_nodes.agent_node.value('(hobt_id/text())[1]', 'bigint') AS hobt_id,
4781 agent_nodes.agent_node.value('(metadata_resource/text()[.="SCHEMA"]/../../metadata_class_id/text())[1]', 'varchar(100)') AS schema_node
4782 FROM #sessions AS s
4783 CROSS APPLY s.additional_info.nodes('//block_info') AS agent_nodes (agent_node)
4784 WHERE
4785 s.recursion = 1
4786 ) AS t
4787 WHERE
4788 t.database_name IS NOT NULL
4789 AND
4790 (
4791 t.object_id IS NOT NULL
4792 OR t.hobt_id IS NOT NULL
4793 OR t.schema_node IS NOT NULL
4794 );
4795
4796 DECLARE blocks_cursor
4797 CURSOR LOCAL FAST_FORWARD
4798 FOR
4799 SELECT DISTINCT
4800 database_name
4801 FROM #blocked_requests;
4802
4803 OPEN blocks_cursor;
4804
4805 FETCH NEXT FROM blocks_cursor
4806 INTO
4807 @database_name;
4808
4809 WHILE @@FETCH_STATUS = 0
4810 BEGIN;
4811 BEGIN TRY;
4812 SET @sql_n =
4813 CONVERT(NVARCHAR(MAX), '') +
4814 'UPDATE b ' +
4815 'SET ' +
4816 'b.schema_name = ' +
4817 'REPLACE ' +
4818 '( ' +
4819 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4820 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4821 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4822 's.name COLLATE Latin1_General_Bin2, ' +
4823 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' +
4824 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' +
4825 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' +
4826 'NCHAR(0), ' +
4827 N''''' ' +
4828 '), ' +
4829 'b.object_name = ' +
4830 'REPLACE ' +
4831 '( ' +
4832 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4833 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4834 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' +
4835 'o.name COLLATE Latin1_General_Bin2, ' +
4836 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' +
4837 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' +
4838 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' +
4839 'NCHAR(0), ' +
4840 N''''' ' +
4841 ') ' +
4842 'FROM #blocked_requests AS b ' +
4843 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.partitions AS p ON ' +
4844 'p.hobt_id = b.hobt_id ' +
4845 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.objects AS o ON ' +
4846 'o.object_id = COALESCE(p.object_id, b.object_id) ' +
4847 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.schemas AS s ON ' +
4848 's.schema_id = COALESCE(o.schema_id, b.schema_id) ' +
4849 'WHERE ' +
4850 'b.database_name = @database_name; ';
4851
4852 EXEC sp_executesql
4853 @sql_n,
4854 N'@database_name sysname',
4855 @database_name;
4856 END TRY
4857 BEGIN CATCH;
4858 UPDATE #blocked_requests
4859 SET
4860 query_error =
4861 REPLACE
4862 (
4863 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4864 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4865 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4866 CONVERT
4867 (
4868 NVARCHAR(MAX),
4869 ERROR_MESSAGE() COLLATE Latin1_General_Bin2
4870 ),
4871 NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'),
4872 NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'),
4873 NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'),
4874 NCHAR(0),
4875 N''
4876 )
4877 WHERE
4878 database_name = @database_name;
4879 END CATCH;
4880
4881 FETCH NEXT FROM blocks_cursor
4882 INTO
4883 @database_name;
4884 END;
4885
4886 CLOSE blocks_cursor;
4887 DEALLOCATE blocks_cursor;
4888
4889 UPDATE s
4890 SET
4891 additional_info.modify
4892 ('
4893 insert <schema_name>{sql:column("b.schema_name")}</schema_name>
4894 as last
4895 into (/additional_info/block_info)[1]
4896 ')
4897 FROM #sessions AS s
4898 INNER JOIN #blocked_requests AS b ON
4899 b.session_id = s.session_id
4900 AND b.request_id = s.request_id
4901 AND s.recursion = 1
4902 WHERE
4903 b.schema_name IS NOT NULL;
4904
4905 UPDATE s
4906 SET
4907 additional_info.modify
4908 ('
4909 insert <object_name>{sql:column("b.object_name")}</object_name>
4910 as last
4911 into (/additional_info/block_info)[1]
4912 ')
4913 FROM #sessions AS s
4914 INNER JOIN #blocked_requests AS b ON
4915 b.session_id = s.session_id
4916 AND b.request_id = s.request_id
4917 AND s.recursion = 1
4918 WHERE
4919 b.object_name IS NOT NULL;
4920
4921 UPDATE s
4922 SET
4923 additional_info.modify
4924 ('
4925 insert <query_error>{sql:column("b.query_error")}</query_error>
4926 as last
4927 into (/additional_info/block_info)[1]
4928 ')
4929 FROM #sessions AS s
4930 INNER JOIN #blocked_requests AS b ON
4931 b.session_id = s.session_id
4932 AND b.request_id = s.request_id
4933 AND s.recursion = 1
4934 WHERE
4935 b.query_error IS NOT NULL;
4936 END;
4937
4938 IF
4939 @output_column_list LIKE '%|[program_name|]%' ESCAPE '|'
4940 AND @output_column_list LIKE '%|[additional_info|]%' ESCAPE '|'
4941 AND @recursion = 1
4942 BEGIN;
4943 DECLARE @job_id UNIQUEIDENTIFIER;
4944 DECLARE @step_id INT;
4945
4946 DECLARE agent_cursor
4947 CURSOR LOCAL FAST_FORWARD
4948 FOR
4949 SELECT
4950 s.session_id,
4951 agent_nodes.agent_node.value('(job_id/text())[1]', 'uniqueidentifier') AS job_id,
4952 agent_nodes.agent_node.value('(step_id/text())[1]', 'int') AS step_id
4953 FROM #sessions AS s
4954 CROSS APPLY s.additional_info.nodes('//agent_job_info') AS agent_nodes (agent_node)
4955 WHERE
4956 s.recursion = 1
4957 OPTION (KEEPFIXED PLAN);
4958
4959 OPEN agent_cursor;
4960
4961 FETCH NEXT FROM agent_cursor
4962 INTO
4963 @session_id,
4964 @job_id,
4965 @step_id;
4966
4967 WHILE @@FETCH_STATUS = 0
4968 BEGIN;
4969 BEGIN TRY;
4970 DECLARE @job_name sysname;
4971 SET @job_name = NULL;
4972 DECLARE @step_name sysname;
4973 SET @step_name = NULL;
4974
4975 SELECT
4976 @job_name =
4977 REPLACE
4978 (
4979 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4980 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4981 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4982 j.name,
4983 NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'),
4984 NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'),
4985 NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'),
4986 NCHAR(0),
4987 N'?'
4988 ),
4989 @step_name =
4990 REPLACE
4991 (
4992 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4993 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4994 REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
4995 s.step_name,
4996 NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'),
4997 NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'),
4998 NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'),
4999 NCHAR(0),
5000 N'?'
5001 )
5002 FROM msdb.dbo.sysjobs AS j
5003 INNER JOIN msdb..sysjobsteps AS s ON
5004 j.job_id = s.job_id
5005 WHERE
5006 j.job_id = @job_id
5007 AND s.step_id = @step_id;
5008
5009 IF @job_name IS NOT NULL
5010 BEGIN;
5011 UPDATE s
5012 SET
5013 additional_info.modify
5014 ('
5015 insert text{sql:variable("@job_name")}
5016 into (/additional_info/agent_job_info/job_name)[1]
5017 ')
5018 FROM #sessions AS s
5019 WHERE
5020 s.session_id = @session_id
5021 OPTION (KEEPFIXED PLAN);
5022
5023 UPDATE s
5024 SET
5025 additional_info.modify
5026 ('
5027 insert text{sql:variable("@step_name")}
5028 into (/additional_info/agent_job_info/step_name)[1]
5029 ')
5030 FROM #sessions AS s
5031 WHERE
5032 s.session_id = @session_id
5033 OPTION (KEEPFIXED PLAN);
5034 END;
5035 END TRY
5036 BEGIN CATCH;
5037 DECLARE @msdb_error_message NVARCHAR(256);
5038 SET @msdb_error_message = ERROR_MESSAGE();
5039
5040 UPDATE s
5041 SET
5042 additional_info.modify
5043 ('
5044 insert <msdb_query_error>{sql:variable("@msdb_error_message")}</msdb_query_error>
5045 as last
5046 into (/additional_info/agent_job_info)[1]
5047 ')
5048 FROM #sessions AS s
5049 WHERE
5050 s.session_id = @session_id
5051 AND s.recursion = 1
5052 OPTION (KEEPFIXED PLAN);
5053 END CATCH;
5054
5055 FETCH NEXT FROM agent_cursor
5056 INTO
5057 @session_id,
5058 @job_id,
5059 @step_id;
5060 END;
5061
5062 CLOSE agent_cursor;
5063 DEALLOCATE agent_cursor;
5064 END;
5065
5066 IF
5067 @delta_interval > 0
5068 AND @recursion <> 1
5069 BEGIN;
5070 SET @recursion = 1;
5071
5072 DECLARE @delay_time CHAR(12);
5073 SET @delay_time = CONVERT(VARCHAR, DATEADD(second, @delta_interval, 0), 114);
5074 WAITFOR DELAY @delay_time;
5075
5076 GOTO REDO;
5077 END;
5078 END;
5079
5080 SET @sql =
5081 --Outer column list
5082 CONVERT
5083 (
5084 VARCHAR(MAX),
5085 CASE
5086 WHEN
5087 @destination_table <> ''
5088 AND @return_schema = 0
5089 THEN 'INSERT ' + @destination_table + ' '
5090 ELSE ''
5091 END +
5092 'SELECT ' +
5093 @output_column_list + ' ' +
5094 CASE @return_schema
5095 WHEN 1 THEN 'INTO #session_schema '
5096 ELSE ''
5097 END
5098 --End outer column list
5099 ) +
5100 --Inner column list
5101 CONVERT
5102 (
5103 VARCHAR(MAX),
5104 'FROM ' +
5105 '( ' +
5106 'SELECT ' +
5107 'session_id, ' +
5108 --[dd hh:mm:ss.mss]
5109 CASE
5110 WHEN @format_output IN (1, 2) THEN
5111 'CASE ' +
5112 'WHEN elapsed_time < 0 THEN ' +
5113 'RIGHT ' +
5114 '( ' +
5115 'REPLICATE(''0'', max_elapsed_length) + CONVERT(VARCHAR, (-1 * elapsed_time) / 86400), ' +
5116 'max_elapsed_length ' +
5117 ') + ' +
5118 'RIGHT ' +
5119 '( ' +
5120 'CONVERT(VARCHAR, DATEADD(second, (-1 * elapsed_time), 0), 120), ' +
5121 '9 ' +
5122 ') + ' +
5123 '''.000'' ' +
5124 'ELSE ' +
5125 'RIGHT ' +
5126 '( ' +
5127 'REPLICATE(''0'', max_elapsed_length) + CONVERT(VARCHAR, elapsed_time / 86400000), ' +
5128 'max_elapsed_length ' +
5129 ') + ' +
5130 'RIGHT ' +
5131 '( ' +
5132 'CONVERT(VARCHAR, DATEADD(second, elapsed_time / 1000, 0), 120), ' +
5133 '9 ' +
5134 ') + ' +
5135 '''.'' + ' +
5136 'RIGHT(''000'' + CONVERT(VARCHAR, elapsed_time % 1000), 3) ' +
5137 'END AS [dd hh:mm:ss.mss], '
5138 ELSE
5139 ''
5140 END +
5141 --[dd hh:mm:ss.mss (avg)] / avg_elapsed_time
5142 CASE
5143 WHEN @format_output IN (1, 2) THEN
5144 'RIGHT ' +
5145 '( ' +
5146 '''00'' + CONVERT(VARCHAR, avg_elapsed_time / 86400000), ' +
5147 '2 ' +
5148 ') + ' +
5149 'RIGHT ' +
5150 '( ' +
5151 'CONVERT(VARCHAR, DATEADD(second, avg_elapsed_time / 1000, 0), 120), ' +
5152 '9 ' +
5153 ') + ' +
5154 '''.'' + ' +
5155 'RIGHT(''000'' + CONVERT(VARCHAR, avg_elapsed_time % 1000), 3) AS [dd hh:mm:ss.mss (avg)], '
5156 ELSE
5157 'avg_elapsed_time, '
5158 END +
5159 --physical_io
5160 CASE @format_output
5161 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_io))) OVER() - LEN(CONVERT(VARCHAR, physical_io))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io), 1), 19)) AS '
5162 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io), 1), 19)) AS '
5163 ELSE ''
5164 END + 'physical_io, ' +
5165 --reads
5166 CASE @format_output
5167 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, reads))) OVER() - LEN(CONVERT(VARCHAR, reads))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads), 1), 19)) AS '
5168 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads), 1), 19)) AS '
5169 ELSE ''
5170 END + 'reads, ' +
5171 --physical_reads
5172 CASE @format_output
5173 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_reads))) OVER() - LEN(CONVERT(VARCHAR, physical_reads))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads), 1), 19)) AS '
5174 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads), 1), 19)) AS '
5175 ELSE ''
5176 END + 'physical_reads, ' +
5177 --writes
5178 CASE @format_output
5179 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, writes))) OVER() - LEN(CONVERT(VARCHAR, writes))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes), 1), 19)) AS '
5180 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes), 1), 19)) AS '
5181 ELSE ''
5182 END + 'writes, ' +
5183 --tempdb_allocations
5184 CASE @format_output
5185 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_allocations))) OVER() - LEN(CONVERT(VARCHAR, tempdb_allocations))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations), 1), 19)) AS '
5186 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations), 1), 19)) AS '
5187 ELSE ''
5188 END + 'tempdb_allocations, ' +
5189 --tempdb_current
5190 CASE @format_output
5191 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_current))) OVER() - LEN(CONVERT(VARCHAR, tempdb_current))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current), 1), 19)) AS '
5192 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current), 1), 19)) AS '
5193 ELSE ''
5194 END + 'tempdb_current, ' +
5195 --CPU
5196 CASE @format_output
5197 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, CPU))) OVER() - LEN(CONVERT(VARCHAR, CPU))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU), 1), 19)) AS '
5198 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU), 1), 19)) AS '
5199 ELSE ''
5200 END + 'CPU, ' +
5201 --context_switches
5202 CASE @format_output
5203 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, context_switches))) OVER() - LEN(CONVERT(VARCHAR, context_switches))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches), 1), 19)) AS '
5204 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches), 1), 19)) AS '
5205 ELSE ''
5206 END + 'context_switches, ' +
5207 --used_memory
5208 CASE @format_output
5209 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, used_memory))) OVER() - LEN(CONVERT(VARCHAR, used_memory))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory), 1), 19)) AS '
5210 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory), 1), 19)) AS '
5211 ELSE ''
5212 END + 'used_memory, ' +
5213 CASE
5214 WHEN @output_column_list LIKE '%|_delta|]%' ESCAPE '|' THEN
5215 --physical_io_delta
5216 'CASE ' +
5217 'WHEN ' +
5218 'first_request_start_time = last_request_start_time ' +
5219 'AND num_events = 2 ' +
5220 'AND physical_io_delta >= 0 ' +
5221 'THEN ' +
5222 CASE @format_output
5223 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_io_delta))) OVER() - LEN(CONVERT(VARCHAR, physical_io_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io_delta), 1), 19)) '
5224 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io_delta), 1), 19)) '
5225 ELSE 'physical_io_delta '
5226 END +
5227 'ELSE NULL ' +
5228 'END AS physical_io_delta, ' +
5229 --reads_delta
5230 'CASE ' +
5231 'WHEN ' +
5232 'first_request_start_time = last_request_start_time ' +
5233 'AND num_events = 2 ' +
5234 'AND reads_delta >= 0 ' +
5235 'THEN ' +
5236 CASE @format_output
5237 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, reads_delta))) OVER() - LEN(CONVERT(VARCHAR, reads_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads_delta), 1), 19)) '
5238 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads_delta), 1), 19)) '
5239 ELSE 'reads_delta '
5240 END +
5241 'ELSE NULL ' +
5242 'END AS reads_delta, ' +
5243 --physical_reads_delta
5244 'CASE ' +
5245 'WHEN ' +
5246 'first_request_start_time = last_request_start_time ' +
5247 'AND num_events = 2 ' +
5248 'AND physical_reads_delta >= 0 ' +
5249 'THEN ' +
5250 CASE @format_output
5251 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_reads_delta))) OVER() - LEN(CONVERT(VARCHAR, physical_reads_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads_delta), 1), 19)) '
5252 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads_delta), 1), 19)) '
5253 ELSE 'physical_reads_delta '
5254 END +
5255 'ELSE NULL ' +
5256 'END AS physical_reads_delta, ' +
5257 --writes_delta
5258 'CASE ' +
5259 'WHEN ' +
5260 'first_request_start_time = last_request_start_time ' +
5261 'AND num_events = 2 ' +
5262 'AND writes_delta >= 0 ' +
5263 'THEN ' +
5264 CASE @format_output
5265 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, writes_delta))) OVER() - LEN(CONVERT(VARCHAR, writes_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes_delta), 1), 19)) '
5266 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes_delta), 1), 19)) '
5267 ELSE 'writes_delta '
5268 END +
5269 'ELSE NULL ' +
5270 'END AS writes_delta, ' +
5271 --tempdb_allocations_delta
5272 'CASE ' +
5273 'WHEN ' +
5274 'first_request_start_time = last_request_start_time ' +
5275 'AND num_events = 2 ' +
5276 'AND tempdb_allocations_delta >= 0 ' +
5277 'THEN ' +
5278 CASE @format_output
5279 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_allocations_delta))) OVER() - LEN(CONVERT(VARCHAR, tempdb_allocations_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations_delta), 1), 19)) '
5280 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations_delta), 1), 19)) '
5281 ELSE 'tempdb_allocations_delta '
5282 END +
5283 'ELSE NULL ' +
5284 'END AS tempdb_allocations_delta, ' +
5285 --tempdb_current_delta
5286 --this is the only one that can (legitimately) go negative
5287 'CASE ' +
5288 'WHEN ' +
5289 'first_request_start_time = last_request_start_time ' +
5290 'AND num_events = 2 ' +
5291 'THEN ' +
5292 CASE @format_output
5293 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_current_delta))) OVER() - LEN(CONVERT(VARCHAR, tempdb_current_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current_delta), 1), 19)) '
5294 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current_delta), 1), 19)) '
5295 ELSE 'tempdb_current_delta '
5296 END +
5297 'ELSE NULL ' +
5298 'END AS tempdb_current_delta, ' +
5299 --CPU_delta
5300 'CASE ' +
5301 'WHEN ' +
5302 'first_request_start_time = last_request_start_time ' +
5303 'AND num_events = 2 ' +
5304 'THEN ' +
5305 'CASE ' +
5306 'WHEN ' +
5307 'thread_CPU_delta > CPU_delta ' +
5308 'AND thread_CPU_delta > 0 ' +
5309 'THEN ' +
5310 CASE @format_output
5311 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, thread_CPU_delta + CPU_delta))) OVER() - LEN(CONVERT(VARCHAR, thread_CPU_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, thread_CPU_delta), 1), 19)) '
5312 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, thread_CPU_delta), 1), 19)) '
5313 ELSE 'thread_CPU_delta '
5314 END +
5315 'WHEN CPU_delta >= 0 THEN ' +
5316 CASE @format_output
5317 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, thread_CPU_delta + CPU_delta))) OVER() - LEN(CONVERT(VARCHAR, CPU_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU_delta), 1), 19)) '
5318 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU_delta), 1), 19)) '
5319 ELSE 'CPU_delta '
5320 END +
5321 'ELSE NULL ' +
5322 'END ' +
5323 'ELSE ' +
5324 'NULL ' +
5325 'END AS CPU_delta, ' +
5326 --context_switches_delta
5327 'CASE ' +
5328 'WHEN ' +
5329 'first_request_start_time = last_request_start_time ' +
5330 'AND num_events = 2 ' +
5331 'AND context_switches_delta >= 0 ' +
5332 'THEN ' +
5333 CASE @format_output
5334 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, context_switches_delta))) OVER() - LEN(CONVERT(VARCHAR, context_switches_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches_delta), 1), 19)) '
5335 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches_delta), 1), 19)) '
5336 ELSE 'context_switches_delta '
5337 END +
5338 'ELSE NULL ' +
5339 'END AS context_switches_delta, ' +
5340 --used_memory_delta
5341 'CASE ' +
5342 'WHEN ' +
5343 'first_request_start_time = last_request_start_time ' +
5344 'AND num_events = 2 ' +
5345 'AND used_memory_delta >= 0 ' +
5346 'THEN ' +
5347 CASE @format_output
5348 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, used_memory_delta))) OVER() - LEN(CONVERT(VARCHAR, used_memory_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory_delta), 1), 19)) '
5349 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory_delta), 1), 19)) '
5350 ELSE 'used_memory_delta '
5351 END +
5352 'ELSE NULL ' +
5353 'END AS used_memory_delta, '
5354 ELSE ''
5355 END +
5356 --tasks
5357 CASE @format_output
5358 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tasks))) OVER() - LEN(CONVERT(VARCHAR, tasks))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tasks), 1), 19)) AS '
5359 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tasks), 1), 19)) '
5360 ELSE ''
5361 END + 'tasks, ' +
5362 'status, ' +
5363 'wait_info, ' +
5364 'locks, ' +
5365 'tran_start_time, ' +
5366 'LEFT(tran_log_writes, LEN(tran_log_writes) - 1) AS tran_log_writes, ' +
5367 --open_tran_count
5368 CASE @format_output
5369 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, open_tran_count))) OVER() - LEN(CONVERT(VARCHAR, open_tran_count))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, open_tran_count), 1), 19)) AS '
5370 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, open_tran_count), 1), 19)) AS '
5371 ELSE ''
5372 END + 'open_tran_count, ' +
5373 --sql_command
5374 CASE @format_output
5375 WHEN 0 THEN 'REPLACE(REPLACE(CONVERT(NVARCHAR(MAX), sql_command), ''<?query --''+CHAR(13)+CHAR(10), ''''), CHAR(13)+CHAR(10)+''--?>'', '''') AS '
5376 ELSE ''
5377 END + 'sql_command, ' +
5378 --sql_text
5379 CASE @format_output
5380 WHEN 0 THEN 'REPLACE(REPLACE(CONVERT(NVARCHAR(MAX), sql_text), ''<?query --''+CHAR(13)+CHAR(10), ''''), CHAR(13)+CHAR(10)+''--?>'', '''') AS '
5381 ELSE ''
5382 END + 'sql_text, ' +
5383 'query_plan, ' +
5384 'blocking_session_id, ' +
5385 --blocked_session_count
5386 CASE @format_output
5387 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, blocked_session_count))) OVER() - LEN(CONVERT(VARCHAR, blocked_session_count))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, blocked_session_count), 1), 19)) AS '
5388 WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, blocked_session_count), 1), 19)) AS '
5389 ELSE ''
5390 END + 'blocked_session_count, ' +
5391 --percent_complete
5392 CASE @format_output
5393 WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, CONVERT(MONEY, percent_complete), 2))) OVER() - LEN(CONVERT(VARCHAR, CONVERT(MONEY, percent_complete), 2))) + CONVERT(CHAR(22), CONVERT(MONEY, percent_complete), 2)) AS '
5394 WHEN 2 THEN 'CONVERT(VARCHAR, CONVERT(CHAR(22), CONVERT(MONEY, blocked_session_count), 1)) AS '
5395 ELSE ''
5396 END + 'percent_complete, ' +
5397 'host_name, ' +
5398 'login_name, ' +
5399 'database_name, ' +
5400 'program_name, ' +
5401 'additional_info, ' +
5402 'start_time, ' +
5403 'login_time, ' +
5404 'CASE ' +
5405 'WHEN status = N''sleeping'' THEN NULL ' +
5406 'ELSE request_id ' +
5407 'END AS request_id, ' +
5408 'GETDATE() AS collection_time '
5409 --End inner column list
5410 ) +
5411 --Derived table and INSERT specification
5412 CONVERT
5413 (
5414 VARCHAR(MAX),
5415 'FROM ' +
5416 '( ' +
5417 'SELECT TOP(2147483647) ' +
5418 '*, ' +
5419 'CASE ' +
5420 'MAX ' +
5421 '( ' +
5422 'LEN ' +
5423 '( ' +
5424 'CONVERT ' +
5425 '( ' +
5426 'VARCHAR, ' +
5427 'CASE ' +
5428 'WHEN elapsed_time < 0 THEN ' +
5429 '(-1 * elapsed_time) / 86400 ' +
5430 'ELSE ' +
5431 'elapsed_time / 86400000 ' +
5432 'END ' +
5433 ') ' +
5434 ') ' +
5435 ') OVER () ' +
5436 'WHEN 1 THEN 2 ' +
5437 'ELSE ' +
5438 'MAX ' +
5439 '( ' +
5440 'LEN ' +
5441 '( ' +
5442 'CONVERT ' +
5443 '( ' +
5444 'VARCHAR, ' +
5445 'CASE ' +
5446 'WHEN elapsed_time < 0 THEN ' +
5447 '(-1 * elapsed_time) / 86400 ' +
5448 'ELSE ' +
5449 'elapsed_time / 86400000 ' +
5450 'END ' +
5451 ') ' +
5452 ') ' +
5453 ') OVER () ' +
5454 'END AS max_elapsed_length, ' +
5455 CASE
5456 WHEN @output_column_list LIKE '%|_delta|]%' ESCAPE '|' THEN
5457 'MAX(physical_io * recursion) OVER (PARTITION BY session_id, request_id) + ' +
5458 'MIN(physical_io * recursion) OVER (PARTITION BY session_id, request_id) AS physical_io_delta, ' +
5459 'MAX(reads * recursion) OVER (PARTITION BY session_id, request_id) + ' +
5460 'MIN(reads * recursion) OVER (PARTITION BY session_id, request_id) AS reads_delta, ' +
5461 'MAX(physical_reads * recursion) OVER (PARTITION BY session_id, request_id) + ' +
5462 'MIN(physical_reads * recursion) OVER (PARTITION BY session_id, request_id) AS physical_reads_delta, ' +
5463 'MAX(writes * recursion) OVER (PARTITION BY session_id, request_id) + ' +
5464 'MIN(writes * recursion) OVER (PARTITION BY session_id, request_id) AS writes_delta, ' +
5465 'MAX(tempdb_allocations * recursion) OVER (PARTITION BY session_id, request_id) + ' +
5466 'MIN(tempdb_allocations * recursion) OVER (PARTITION BY session_id, request_id) AS tempdb_allocations_delta, ' +
5467 'MAX(tempdb_current * recursion) OVER (PARTITION BY session_id, request_id) + ' +
5468 'MIN(tempdb_current * recursion) OVER (PARTITION BY session_id, request_id) AS tempdb_current_delta, ' +
5469 'MAX(CPU * recursion) OVER (PARTITION BY session_id, request_id) + ' +
5470 'MIN(CPU * recursion) OVER (PARTITION BY session_id, request_id) AS CPU_delta, ' +
5471 'MAX(thread_CPU_snapshot * recursion) OVER (PARTITION BY session_id, request_id) + ' +
5472 'MIN(thread_CPU_snapshot * recursion) OVER (PARTITION BY session_id, request_id) AS thread_CPU_delta, ' +
5473 'MAX(context_switches * recursion) OVER (PARTITION BY session_id, request_id) + ' +
5474 'MIN(context_switches * recursion) OVER (PARTITION BY session_id, request_id) AS context_switches_delta, ' +
5475 'MAX(used_memory * recursion) OVER (PARTITION BY session_id, request_id) + ' +
5476 'MIN(used_memory * recursion) OVER (PARTITION BY session_id, request_id) AS used_memory_delta, ' +
5477 'MIN(last_request_start_time) OVER (PARTITION BY session_id, request_id) AS first_request_start_time, '
5478 ELSE ''
5479 END +
5480 'COUNT(*) OVER (PARTITION BY session_id, request_id) AS num_events ' +
5481 'FROM #sessions AS s1 ' +
5482 CASE
5483 WHEN @sort_order = '' THEN ''
5484 ELSE
5485 'ORDER BY ' +
5486 @sort_order
5487 END +
5488 ') AS s ' +
5489 'WHERE ' +
5490 's.recursion = 1 ' +
5491 ') x ' +
5492 'OPTION (KEEPFIXED PLAN); ' +
5493 '' +
5494 CASE @return_schema
5495 WHEN 1 THEN
5496 'SET @schema = ' +
5497 '''CREATE TABLE <table_name> ( '' + ' +
5498 'STUFF ' +
5499 '( ' +
5500 '( ' +
5501 'SELECT ' +
5502 ''','' + ' +
5503 'QUOTENAME(COLUMN_NAME) + '' '' + ' +
5504 'DATA_TYPE + ' +
5505 'CASE ' +
5506 'WHEN DATA_TYPE LIKE ''%char'' THEN ''('' + COALESCE(NULLIF(CONVERT(VARCHAR, CHARACTER_MAXIMUM_LENGTH), ''-1''), ''max'') + '') '' ' +
5507 'ELSE '' '' ' +
5508 'END + ' +
5509 'CASE IS_NULLABLE ' +
5510 'WHEN ''NO'' THEN ''NOT '' ' +
5511 'ELSE '''' ' +
5512 'END + ''NULL'' AS [text()] ' +
5513 'FROM tempdb.INFORMATION_SCHEMA.COLUMNS ' +
5514 'WHERE ' +
5515 'TABLE_NAME = (SELECT name FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(''tempdb..#session_schema'')) ' +
5516 'ORDER BY ' +
5517 'ORDINAL_POSITION ' +
5518 'FOR XML ' +
5519 'PATH('''') ' +
5520 '), + ' +
5521 '1, ' +
5522 '1, ' +
5523 ''''' ' +
5524 ') + ' +
5525 ''')''; '
5526 ELSE ''
5527 END
5528 --End derived table and INSERT specification
5529 );
5530
5531 SET @sql_n = CONVERT(NVARCHAR(MAX), @sql);
5532
5533 EXEC sp_executesql
5534 @sql_n,
5535 N'@schema VARCHAR(MAX) OUTPUT',
5536 @schema OUTPUT;
5537END;
5538GO
5539----------------------------------------------------------------------------------------------
5540-- Install SP_AskBrent
5541----------------------------------------------------------------------------------------------
5542USE [master];
5543GO
5544
5545IF OBJECT_ID('dbo.sp_AskBrent') IS NULL
5546 EXEC ('CREATE PROCEDURE dbo.sp_AskBrent AS RETURN 0;')
5547GO
5548
5549
5550ALTER PROCEDURE [dbo].[sp_AskBrent]
5551 @Question NVARCHAR(MAX) = NULL ,
5552 @AsOf DATETIME = NULL ,
5553 @ExpertMode TINYINT = 0 ,
5554 @Seconds INT = 5 ,
5555 @OutputType VARCHAR(20) = 'TABLE' ,
5556 @OutputDatabaseName NVARCHAR(128) = NULL ,
5557 @OutputSchemaName NVARCHAR(256) = NULL ,
5558 @OutputTableName NVARCHAR(256) = NULL ,
5559 @OutputXMLasNVARCHAR TINYINT = 0 ,
5560 @FilterPlansByDatabase VARCHAR(MAX) = NULL ,
5561 @Version INT = NULL OUTPUT,
5562 @VersionDate DATETIME = NULL OUTPUT
5563 WITH EXECUTE AS CALLER, RECOMPILE
5564AS
5565BEGIN
5566SET NOCOUNT ON;
5567SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
5568
5569/*
5570sp_AskBrent (TM)
5571
5572(C) 2014, Brent Ozar Unlimited.
5573See http://BrentOzar.com/go/eula for the End User Licensing Agreement.
5574
5575Sure, the server needs tuning - but why is it slow RIGHT NOW?
5576sp_AskBrent performs quick checks for things like:
5577
5578* Blocking queries that have been running a long time
5579* Backups, restores, DBCCs
5580* Recently cleared plan cache
5581* Transactions that are rolling back
5582
5583To learn more, visit http://www.BrentOzar.com/askbrent/ where you can download
5584new versions for free, watch training videos on how it works, get more info on
5585the findings, and more. To contribute code and see your name in the change
5586log, email your improvements & checks to Help@BrentOzar.com.
5587
5588Known limitations of this version:
5589 - No support for SQL Server 2000 or compatibility mode 80.
5590 - If a temp table called #CustomPerfmonCounters exists for any other session,
5591 but not our session, this stored proc will fail with an error saying the
5592 temp table #CustomPerfmonCounters doesn't exist.
5593
5594Unknown limitations of this version:
5595 - None. Like Zombo.com, the only limit is yourself.
5596
5597Changes in v10 - May 22, 2014
5598 - Added some new SQL 2014 harmless wait stats like
5599 QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP.
5600 - Added ExpertMode columns for more plan cache metrics analysis on the query's
5601 percentage of the server's load during the sample, plus overall load.
5602 - Added @OutputType = 'Opserver1' to output results in a format that works
5603 better for Opserver, the open source monitoring tool of champions. Get it:
5604 https://github.com/opserver/Opserver
5605 - Added thresholds to Most Resource-Intensive Queries. Now requires 1000 page
5606 reads, 1 second of CPU time, or 1 second of duration before queries are
5607 shown. This prevents the "idle presenter laptop" problem where IntelliSense
5608 queries show up as resource-intensive.
5609 - Added DatabaseID, DatabaseName for query plans when ExpertMode = 1.
5610 - Added @FilterPlansByDatabase. Takes a comma-delimited list of database IDs
5611 and only looks for resource-intensive plans in those databases. Also takes
5612 the parameter 'USER' for only user databases.
5613 - Creation script now defaults to ALTER PROCEDURE instead of CREATE.
5614 - Raised compilations/sec and recompilations/sec thresholds to 100/sec.
5615
5616Changes in v9 - Nov 3, 2013
5617 - Changed date format to accommodate the British. They gave us Gordon Ramsay,
5618 so it's the least I could do. Many folks reported this one.
5619
5620Changes in v8 - October 21, 2013
5621 - Whoops! Left an extra line in check 8 that failed on SQL 2005.
5622
5623Changes in v7 - October 21, 2013
5624 - Updated many of the links to point to newly published pages.
5625 - Performance tuning Check 8 (sleeping connections with open transactions).
5626 Went from >1 minute at StackExchange to <10 seconds.
5627
5628Changes in v6 - October 11, 2013
5629 - Time travel enabled. Can log to database using the @Output* parameters, and
5630 you can go back in time with the @AsOf parameter.
5631 - Bug fixing for SQL Server 2005 compatibility.
5632
5633Changes in v5 - September 16, 2013
5634 - Enabled @Question again.
5635 - Bail out of plan cache analysis if we're more than 10 seconds behind.
5636
5637Changes in v4 - August 25, 2013
5638 - Added plan cache analysis.
5639 - Fixed checkid 8 (sleeping query with open transactions) for SQL 2005/08/R2.
5640 - Refactored a little for readability.
5641 - Added QueryPlan to the default results because the plan cache stuff is cool.
5642
5643Changes in v3 - August 23, 2013
5644 - Added @OutputType = 'SCHEMA', which returns the version number and a list
5645 of columns for a CREATE TABLE definition for the default outputs. We don't
5646 include the actual CREATE TABLE part because you might want to use a table
5647 variable or whatever.
5648 - Added @OutputXMLasNVARCHAR. If 1, then the QueryPlan is outputted as an
5649 NVARCHAR(MAX) instead of XML. This helps if you want to insert the
5650 sp_AskBrent results into a temp table. For instructions, visit:
5651
5652Changes in v2 - August 9, 2013
5653 - Added @Seconds to control the sampling time.
5654 - @ExpertMode now returns all work tables with no thresholds.
5655 - Added basic wait stats, file stats, Perfmon checks.
5656
5657Changes in v1 - July 11, 2013
5658 - Initial bug-filled release. We purposely left extra errors on here so
5659 you could email bug reports to Help@BrentOzar.com, thereby increasing
5660 your self-esteem. It's all about you.
5661*/
5662
5663
5664SELECT @Version = 10, @VersionDate = '20140122'
5665
5666DECLARE @StringToExecute NVARCHAR(4000),
5667 @OurSessionID INT,
5668 @LineFeed NVARCHAR(10),
5669 @StockWarningHeader NVARCHAR(500),
5670 @StockWarningFooter NVARCHAR(100),
5671 @StockDetailsHeader NVARCHAR(100),
5672 @StockDetailsFooter NVARCHAR(100),
5673 @StartSampleTime DATETIME,
5674 @FinishSampleTime DATETIME;
5675
5676/* Sanitize our inputs */
5677SELECT
5678 @OutputDatabaseName = QUOTENAME(@OutputDatabaseName),
5679 @OutputSchemaName = QUOTENAME(@OutputSchemaName),
5680 @OutputTableName = QUOTENAME(@OutputTableName),
5681 @LineFeed = CHAR(13) + CHAR(10),
5682 @StartSampleTime = GETDATE(),
5683 @FinishSampleTime = DATEADD(ss, @Seconds, GETDATE()),
5684 @OurSessionID = @@SPID;
5685
5686IF @OutputType = 'SCHEMA'
5687BEGIN
5688 SELECT @Version AS Version,
5689 FieldList = '[Priority] TINYINT, [FindingsGroup] VARCHAR(50), [Finding] VARCHAR(200), [URL] VARCHAR(200), [Details] NVARCHAR(4000), [HowToStopIt] NVARCHAR(MAX), [QueryPlan] XML, [QueryText] NVARCHAR(MAX)'
5690
5691END
5692ELSE IF @AsOf IS NOT NULL AND @OutputDatabaseName IS NOT NULL AND @OutputSchemaName IS NOT NULL AND @OutputTableName IS NOT NULL
5693BEGIN
5694 /* They want to look into the past. */
5695
5696 SET @StringToExecute = N' IF EXISTS(SELECT * FROM '
5697 + @OutputDatabaseName
5698 + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
5699 + @OutputSchemaName + ''') SELECT CheckDate, [Priority], [FindingsGroup], [Finding], [URL], CAST([Details] AS [XML]) AS Details,'
5700 + '[HowToStopIt], [CheckID], [StartTime], [LoginName], [NTUserName], [OriginalLoginName], [ProgramName], [HostName], [DatabaseID],'
5701 + '[DatabaseName], [OpenTransactionCount], [QueryPlan], [QueryText] FROM '
5702 + @OutputDatabaseName + '.'
5703 + @OutputSchemaName + '.'
5704 + @OutputTableName
5705 + ' WHERE CheckDate >= DATEADD(mi, -15, ''' + CAST(@AsOf AS NVARCHAR(100)) + ''')'
5706 + ' AND CheckDate <= DATEADD(mi, 15, ''' + CAST(@AsOf AS NVARCHAR(100)) + ''')'
5707 + ' /*ORDER BY CheckDate, Priority , FindingsGroup , Finding , Details*/;';
5708 EXEC(@StringToExecute);
5709
5710
5711END /* IF @AsOf IS NOT NULL AND @OutputDatabaseName IS NOT NULL AND @OutputSchemaName IS NOT NULL AND @OutputTableName IS NOT NULL */
5712ELSE IF @Question IS NULL /* IF @OutputType = 'SCHEMA' */
5713BEGIN
5714
5715
5716 /*
5717 We start by creating #AskBrentResults. It's a temp table that will storef
5718 the results from our checks. Throughout the rest of this stored procedure,
5719 we're running a series of checks looking for dangerous things inside the SQL
5720 Server. When we find a problem, we insert rows into #BlitzResults. At the
5721 end, we return these results to the end user.
5722
5723 #AskBrentResults has a CheckID field, but there's no Check table. As we do
5724 checks, we insert data into this table, and we manually put in the CheckID.
5725 We (Brent Ozar Unlimited) maintain a list of the checks by ID#. You can
5726 download that from http://www.BrentOzar.com/askbrent/documentation/ if you
5727 want to build a tool that relies on the output of sp_AskBrent.
5728 */
5729
5730 IF OBJECT_ID('tempdb..#AskBrentResults') IS NOT NULL
5731 DROP TABLE #AskBrentResults;
5732 CREATE TABLE #AskBrentResults
5733 (
5734 ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
5735 CheckID INT NOT NULL,
5736 Priority TINYINT NOT NULL,
5737 FindingsGroup VARCHAR(50) NOT NULL,
5738 Finding VARCHAR(200) NOT NULL,
5739 URL VARCHAR(200) NOT NULL,
5740 Details NVARCHAR(4000) NULL,
5741 HowToStopIt NVARCHAR(MAX) NULL,
5742 QueryPlan [XML] NULL,
5743 QueryText NVARCHAR(MAX) NULL,
5744 StartTime DATETIME NULL,
5745 LoginName NVARCHAR(128) NULL,
5746 NTUserName NVARCHAR(128) NULL,
5747 OriginalLoginName NVARCHAR(128) NULL,
5748 ProgramName NVARCHAR(128) NULL,
5749 HostName NVARCHAR(128) NULL,
5750 DatabaseID INT NULL,
5751 DatabaseName NVARCHAR(128) NULL,
5752 OpenTransactionCount INT NULL,
5753 QueryStatsNowID INT NULL,
5754 QueryStatsFirstID INT NULL,
5755 PlanHandle VARBINARY(64)
5756 );
5757
5758 IF OBJECT_ID('tempdb..#WaitStats') IS NOT NULL
5759 DROP TABLE #WaitStats;
5760 CREATE TABLE #WaitStats (Pass TINYINT NOT NULL, wait_type NVARCHAR(60), wait_time_ms BIGINT, signal_wait_time_ms BIGINT, waiting_tasks_count BIGINT, SampleTime DATETIME);
5761
5762 IF OBJECT_ID('tempdb..#FileStats') IS NOT NULL
5763 DROP TABLE #FileStats;
5764 CREATE TABLE #FileStats (
5765 ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
5766 Pass TINYINT NOT NULL,
5767 SampleTime DATETIME NOT NULL,
5768 DatabaseID INT NOT NULL,
5769 FileID INT NOT NULL,
5770 DatabaseName NVARCHAR(256) ,
5771 FileLogicalName NVARCHAR(256) ,
5772 TypeDesc NVARCHAR(60) ,
5773 SizeOnDiskMB BIGINT ,
5774 io_stall_read_ms BIGINT ,
5775 num_of_reads BIGINT ,
5776 bytes_read BIGINT ,
5777 io_stall_write_ms BIGINT ,
5778 num_of_writes BIGINT ,
5779 bytes_written BIGINT,
5780 PhysicalName NVARCHAR(520) ,
5781 avg_stall_read_ms INT ,
5782 avg_stall_write_ms INT
5783 );
5784
5785 IF OBJECT_ID('tempdb..#QueryStats') IS NOT NULL
5786 DROP TABLE #QueryStats;
5787 CREATE TABLE #QueryStats (
5788 ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
5789 Pass INT NOT NULL,
5790 SampleTime DATETIME NOT NULL,
5791 [sql_handle] VARBINARY(64),
5792 statement_start_offset INT,
5793 statement_end_offset INT,
5794 plan_generation_num BIGINT,
5795 plan_handle VARBINARY(64),
5796 execution_count BIGINT,
5797 total_worker_time BIGINT,
5798 total_physical_reads BIGINT,
5799 total_logical_writes BIGINT,
5800 total_logical_reads BIGINT,
5801 total_clr_time BIGINT,
5802 total_elapsed_time BIGINT,
5803 creation_time DATETIME,
5804 query_hash BINARY(8),
5805 query_plan_hash BINARY(8),
5806 Points TINYINT
5807 );
5808
5809 IF OBJECT_ID('tempdb..#PerfmonStats') IS NOT NULL
5810 DROP TABLE #PerfmonStats;
5811 CREATE TABLE #PerfmonStats (
5812 ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
5813 Pass TINYINT NOT NULL,
5814 SampleTime DATETIME NOT NULL,
5815 [object_name] NVARCHAR(128) NOT NULL,
5816 [counter_name] NVARCHAR(128) NOT NULL,
5817 [instance_name] NVARCHAR(128) NULL,
5818 [cntr_value] BIGINT NULL,
5819 [cntr_type] INT NOT NULL,
5820 [value_delta] BIGINT NULL,
5821 [value_per_second] DECIMAL(18,2) NULL
5822 );
5823
5824 IF OBJECT_ID('tempdb..#PerfmonCounters') IS NOT NULL
5825 DROP TABLE #PerfmonCounters;
5826 CREATE TABLE #PerfmonCounters (
5827 ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
5828 [object_name] NVARCHAR(128) NOT NULL,
5829 [counter_name] NVARCHAR(128) NOT NULL,
5830 [instance_name] NVARCHAR(128) NULL
5831 );
5832
5833 IF OBJECT_ID('tempdb..#FilterPlansByDatabase') IS NOT NULL
5834 DROP TABLE #FilterPlansByDatabase;
5835 CREATE TABLE #FilterPlansByDatabase (DatabaseID INT PRIMARY KEY CLUSTERED);
5836
5837 IF @FilterPlansByDatabase IS NOT NULL
5838 BEGIN
5839 IF UPPER(LEFT(@FilterPlansByDatabase,4)) = 'USER'
5840 BEGIN
5841 INSERT INTO #FilterPlansByDatabase (DatabaseID)
5842 SELECT database_id
5843 FROM sys.databases
5844 WHERE [name] NOT IN ('master', 'model', 'msdb', 'tempdb')
5845 END
5846 ELSE
5847 BEGIN
5848 SET @FilterPlansByDatabase = @FilterPlansByDatabase + ','
5849 ;WITH a AS
5850 (
5851 SELECT CAST(1 AS BIGINT) f, CHARINDEX(',', @FilterPlansByDatabase) t, 1 SEQ
5852 UNION ALL
5853 SELECT t + 1, CHARINDEX(',', @FilterPlansByDatabase, t + 1), SEQ + 1
5854 FROM a
5855 WHERE CHARINDEX(',', @FilterPlansByDatabase, t + 1) > 0
5856 )
5857 INSERT #FilterPlansByDatabase (DatabaseID)
5858 SELECT SUBSTRING(@FilterPlansByDatabase, f, t - f)
5859 FROM a
5860 WHERE SUBSTRING(@FilterPlansByDatabase, f, t - f) IS NOT NULL
5861 OPTION (MAXRECURSION 0)
5862 END
5863 END
5864
5865
5866 SET @StockWarningHeader = '<?ClickToSeeCommmand -- ' + @LineFeed + @LineFeed
5867 + 'WARNING: Running this command may result in data loss or an outage.' + @LineFeed
5868 + 'This tool is meant as a shortcut to help generate scripts for DBAs.' + @LineFeed
5869 + 'It is not a substitute for database training and experience.' + @LineFeed
5870 + 'Now, having said that, here''s the details:' + @LineFeed + @LineFeed;
5871
5872 SELECT @StockWarningFooter = @LineFeed + @LineFeed + '-- ?>',
5873 @StockDetailsHeader = '<?ClickToSeeDetails -- ' + @LineFeed,
5874 @StockDetailsFooter = @LineFeed + ' -- ?>';
5875
5876 /* Build a list of queries that were run in the last 10 seconds.
5877 We're looking for the death-by-a-thousand-small-cuts scenario
5878 where a query is constantly running, and it doesn't have that
5879 big of an impact individually, but it has a ton of impact
5880 overall. We're going to build this list, and then after we
5881 finish our @Seconds sample, we'll compare our plan cache to
5882 this list to see what ran the most. */
5883
5884 /* Populate #QueryStats. SQL 2005 doesn't have query hash or query plan hash. */
5885 IF @@VERSION LIKE 'Microsoft SQL Server 2005%'
5886 BEGIN
5887 IF @FilterPlansByDatabase IS NULL
5888 BEGIN
5889 SET @StringToExecute = N'INSERT INTO #QueryStats ([sql_handle], Pass, SampleTime, statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, query_hash, query_plan_hash, Points)
5890 SELECT [sql_handle], 1 AS Pass, GETDATE(), statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, NULL AS query_hash, NULL AS query_plan_hash, 0
5891 FROM sys.dm_exec_query_stats qs
5892 WHERE qs.last_execution_time >= (DATEADD(ss, -10, GETDATE()));';
5893 END
5894 ELSE
5895 BEGIN
5896 SET @StringToExecute = N'INSERT INTO #QueryStats ([sql_handle], Pass, SampleTime, statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, query_hash, query_plan_hash, Points)
5897 SELECT [sql_handle], 1 AS Pass, GETDATE(), statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, NULL AS query_hash, NULL AS query_plan_hash, 0
5898 FROM sys.dm_exec_query_stats qs
5899 CROSS APPLY sys.dm_exec_plan_attributes(qs.plan_handle) AS attr
5900 INNER JOIN #FilterPlansByDatabase dbs ON CAST(attr.value AS INT) = dbs.DatabaseID
5901 WHERE qs.last_execution_time >= (DATEADD(ss, -10, GETDATE()))
5902 AND attr.attribute = ''dbid'';';
5903 END
5904 END
5905 ELSE
5906 BEGIN
5907 IF @FilterPlansByDatabase IS NULL
5908 BEGIN
5909 SET @StringToExecute = N'INSERT INTO #QueryStats ([sql_handle], Pass, SampleTime, statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, query_hash, query_plan_hash, Points)
5910 SELECT [sql_handle], 1 AS Pass, GETDATE(), statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, query_hash, query_plan_hash, 0
5911 FROM sys.dm_exec_query_stats qs
5912 WHERE qs.last_execution_time >= (DATEADD(ss, -10, GETDATE()));';
5913 END
5914 ELSE
5915 BEGIN
5916 SET @StringToExecute = N'INSERT INTO #QueryStats ([sql_handle], Pass, SampleTime, statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, query_hash, query_plan_hash, Points)
5917 SELECT [sql_handle], 1 AS Pass, GETDATE(), statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, query_hash, query_plan_hash, 0
5918 FROM sys.dm_exec_query_stats qs
5919 CROSS APPLY sys.dm_exec_plan_attributes(qs.plan_handle) AS attr
5920 INNER JOIN #FilterPlansByDatabase dbs ON CAST(attr.value AS INT) = dbs.DatabaseID
5921 WHERE qs.last_execution_time >= (DATEADD(ss, -10, GETDATE()))
5922 AND attr.attribute = ''dbid'';';
5923 END
5924 END
5925 EXEC(@StringToExecute);
5926
5927 /* Get the totals for the entire plan cache */
5928 INSERT INTO #QueryStats (Pass, SampleTime, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time)
5929 SELECT -1 AS Pass, GETDATE(), SUM(execution_count), SUM(total_worker_time), SUM(total_physical_reads), SUM(total_logical_writes), SUM(total_logical_reads), SUM(total_clr_time), SUM(total_elapsed_time), MIN(creation_time)
5930 FROM sys.dm_exec_query_stats qs;
5931
5932
5933 IF EXISTS (SELECT *
5934 FROM tempdb.sys.all_objects obj
5935 INNER JOIN tempdb.sys.all_columns col1 ON obj.object_id = col1.object_id AND col1.name = 'object_name'
5936 INNER JOIN tempdb.sys.all_columns col2 ON obj.object_id = col2.object_id AND col2.name = 'counter_name'
5937 INNER JOIN tempdb.sys.all_columns col3 ON obj.object_id = col3.object_id AND col3.name = 'instance_name'
5938 WHERE obj.name LIKE '%CustomPerfmonCounters%')
5939 BEGIN
5940 SET @StringToExecute = 'INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) SELECT [object_name],[counter_name],[instance_name] FROM #CustomPerfmonCounters'
5941 EXEC(@StringToExecute);
5942 END
5943 ELSE
5944 BEGIN
5945 /* Add our default Perfmon counters */
5946 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Forwarded Records/sec', NULL)
5947 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Page compression attempts/sec', NULL)
5948 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Page Splits/sec', NULL)
5949 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Skipped Ghosted Records/sec', NULL)
5950 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Table Lock Escalations/sec', NULL)
5951 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Worktables Created/sec', NULL)
5952 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Page life expectancy', NULL)
5953 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Page reads/sec', NULL)
5954 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Page writes/sec', NULL)
5955 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Readahead pages/sec', NULL)
5956 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Target pages', NULL)
5957 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Total pages', NULL)
5958 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Databases','', NULL)
5959 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Active Transactions','_Total')
5960 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Databases','Log Growths', '_Total')
5961 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Databases','Log Shrinks', '_Total')
5962 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Exec Statistics','Distributed Query', 'Execs in progress')
5963 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Exec Statistics','DTC calls', 'Execs in progress')
5964 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Exec Statistics','Extended Procedures', 'Execs in progress')
5965 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Exec Statistics','OLEDB calls', 'Execs in progress')
5966 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:General Statistics','Active Temp Tables', NULL)
5967 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:General Statistics','Logins/sec', NULL)
5968 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:General Statistics','Logouts/sec', NULL)
5969 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:General Statistics','Mars Deadlocks', NULL)
5970 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:General Statistics','Processes blocked', NULL)
5971 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Locks','Number of Deadlocks/sec', NULL)
5972 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Memory Manager','Memory Grants Pending', NULL)
5973 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Errors','Errors/sec', '_Total')
5974 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','Batch Requests/sec', NULL)
5975 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','Forced Parameterizations/sec', NULL)
5976 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','Guided plan executions/sec', NULL)
5977 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','SQL Attention rate', NULL)
5978 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','SQL Compilations/sec', NULL)
5979 INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','SQL Re-Compilations/sec', NULL)
5980 END
5981
5982 /* Populate #FileStats, #PerfmonStats, #WaitStats with DMV data.
5983 After we finish doing our checks, we'll take another sample and compare them. */
5984 INSERT #WaitStats(Pass, SampleTime, wait_type, wait_time_ms, signal_wait_time_ms, waiting_tasks_count)
5985 SELECT
5986 1 AS Pass,
5987 GETDATE() AS SampleTime,
5988 os.wait_type,
5989 SUM(os.wait_time_ms) OVER (PARTITION BY os.wait_type) as sum_wait_time_ms,
5990 SUM(os.signal_wait_time_ms) OVER (PARTITION BY os.wait_type ) as sum_signal_wait_time_ms,
5991 SUM(os.waiting_tasks_count) OVER (PARTITION BY os.wait_type) AS sum_waiting_tasks
5992 FROM sys.dm_os_wait_stats os
5993 WHERE os.wait_type not in (
5994 'REQUEST_FOR_DEADLOCK_SEARCH',
5995 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
5996 'SQLTRACE_BUFFER_FLUSH',
5997 'LAZYWRITER_SLEEP',
5998 'XE_TIMER_EVENT',
5999 'XE_DISPATCHER_WAIT',
6000 'FT_IFTS_SCHEDULER_IDLE_WAIT',
6001 'LOGMGR_QUEUE',
6002 'CHECKPOINT_QUEUE',
6003 'BROKER_TO_FLUSH',
6004 'BROKER_TASK_STOP',
6005 'BROKER_EVENTHANDLER',
6006 'SLEEP_TASK',
6007 'WAITFOR',
6008 'DBMIRROR_DBM_MUTEX',
6009 'DBMIRROR_EVENTS_QUEUE',
6010 'DBMIRRORING_CMD',
6011 'DISPATCHER_QUEUE_SEMAPHORE',
6012 'BROKER_RECEIVE_WAITFOR',
6013 'CLR_AUTO_EVENT',
6014 'DIRTY_PAGE_POLL',
6015 'HADR_FILESTREAM_IOMGR_IOCOMPLETION',
6016 'ONDEMAND_TASK_QUEUE',
6017 'FT_IFTSHC_MUTEX',
6018 'CLR_MANUAL_EVENT',
6019 'CLR_SEMAPHORE',
6020 'DBMIRROR_WORKER_QUEUE',
6021 'DBMIRROR_DBM_EVENT',
6022 'SP_SERVER_DIAGNOSTICS_SLEEP',
6023 'HADR_CLUSAPI_CALL',
6024 'HADR_LOGCAPTURE_WAIT',
6025 'HADR_NOTIFICATION_DEQUEUE',
6026 'HADR_TIMER_TASK',
6027 'HADR_WORK_QUEUE',
6028 'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP',
6029 'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP'
6030 )
6031 ORDER BY sum_wait_time_ms DESC;
6032
6033
6034 INSERT INTO #FileStats (Pass, SampleTime, DatabaseID, FileID, DatabaseName, FileLogicalName, SizeOnDiskMB, io_stall_read_ms ,
6035 num_of_reads, [bytes_read] , io_stall_write_ms,num_of_writes, [bytes_written], PhysicalName, TypeDesc)
6036 SELECT
6037 1 AS Pass,
6038 GETDATE() AS SampleTime,
6039 mf.[database_id],
6040 mf.[file_id],
6041 DB_NAME(vfs.database_id) AS [db_name],
6042 mf.name + N' [' + mf.type_desc COLLATE SQL_Latin1_General_CP1_CI_AS + N']' AS file_logical_name ,
6043 CAST(( ( vfs.size_on_disk_bytes / 1024.0 ) / 1024.0 ) AS INT) AS size_on_disk_mb ,
6044 vfs.io_stall_read_ms ,
6045 vfs.num_of_reads ,
6046 vfs.[num_of_bytes_read],
6047 vfs.io_stall_write_ms ,
6048 vfs.num_of_writes ,
6049 vfs.[num_of_bytes_written],
6050 mf.physical_name,
6051 mf.type_desc
6052 FROM sys.dm_io_virtual_file_stats (NULL, NULL) AS vfs
6053 INNER JOIN sys.master_files AS mf ON vfs.file_id = mf.file_id
6054 AND vfs.database_id = mf.database_id
6055 WHERE vfs.num_of_reads > 0
6056 OR vfs.num_of_writes > 0;
6057
6058 INSERT INTO #PerfmonStats (Pass, SampleTime, [object_name],[counter_name],[instance_name],[cntr_value],[cntr_type])
6059 SELECT 1 AS Pass,
6060 GETDATE() AS SampleTime, RTRIM(dmv.object_name), RTRIM(dmv.counter_name), RTRIM(dmv.instance_name), dmv.cntr_value, dmv.cntr_type
6061 FROM #PerfmonCounters counters
6062 INNER JOIN sys.dm_os_performance_counters dmv ON counters.counter_name = RTRIM(dmv.counter_name)
6063 AND counters.[object_name] = RTRIM(dmv.[object_name])
6064 AND (counters.[instance_name] IS NULL OR counters.[instance_name] = RTRIM(dmv.[instance_name]))
6065
6066 /* Maintenance Tasks Running - Backup Running - CheckID 1 */
6067 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
6068 SELECT 1 AS CheckID,
6069 1 AS Priority,
6070 'Maintenance Tasks Running' AS FindingGroup,
6071 'Backup Running' AS Finding,
6072 'http://BrentOzar.com/askbrent/backups/' AS URL,
6073 'Backup of ' + DB_NAME(db.resource_database_id) + ' database (' + (SELECT CAST(CAST(SUM(size * 8.0 / 1024 / 1024) AS BIGINT) AS NVARCHAR) FROM sys.master_files WHERE database_id = db.resource_database_id) + 'GB) is ' + CAST(r.percent_complete AS NVARCHAR(100)) + '% complete, has been running since ' + CAST(r.start_time AS NVARCHAR(100)) + '. ' AS Details,
6074 'KILL ' + CAST(r.session_id AS NVARCHAR(100)) + ';' AS HowToStopIt,
6075 pl.query_plan AS QueryPlan,
6076 r.start_time AS StartTime,
6077 s.login_name AS LoginName,
6078 s.nt_user_name AS NTUserName,
6079 s.[program_name] AS ProgramName,
6080 s.[host_name] AS HostName,
6081 db.[resource_database_id] AS DatabaseID,
6082 DB_NAME(db.resource_database_id) AS DatabaseName,
6083 0 AS OpenTransactionCount
6084 FROM sys.dm_exec_requests r
6085 INNER JOIN sys.dm_exec_connections c ON r.session_id = c.session_id
6086 INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
6087 INNER JOIN (
6088 SELECT DISTINCT request_session_id, resource_database_id
6089 FROM sys.dm_tran_locks
6090 WHERE resource_type = N'DATABASE'
6091 AND request_mode = N'S'
6092 AND request_status = N'GRANT'
6093 AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
6094 CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
6095 WHERE r.command LIKE 'BACKUP%';
6096
6097
6098 /* If there's a backup running, add details explaining how long full backup has been taking in the last month. */
6099 UPDATE #AskBrentResults
6100 SET Details = Details + ' Over the last 60 days, the full backup usually takes ' + CAST((SELECT AVG(DATEDIFF(mi, bs.backup_start_date, bs.backup_finish_date)) FROM msdb.dbo.backupset bs WHERE abr.DatabaseName = bs.database_name AND bs.type = 'D' AND bs.backup_start_date > DATEADD(dd, -60, GETDATE()) AND bs.backup_finish_date IS NOT NULL) AS NVARCHAR(100)) + ' minutes.'
6101 FROM #AskBrentResults abr
6102 WHERE abr.CheckID = 1 AND EXISTS (SELECT * FROM msdb.dbo.backupset bs WHERE bs.type = 'D' AND bs.backup_start_date > DATEADD(dd, -60, GETDATE()) AND bs.backup_finish_date IS NOT NULL AND abr.DatabaseName = bs.database_name AND DATEDIFF(mi, bs.backup_start_date, bs.backup_finish_date) > 1)
6103
6104
6105
6106 /* Maintenance Tasks Running - DBCC Running - CheckID 2 */
6107 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
6108 SELECT 2 AS CheckID,
6109 1 AS Priority,
6110 'Maintenance Tasks Running' AS FindingGroup,
6111 'DBCC Running' AS Finding,
6112 'http://BrentOzar.com/askbrent/dbcc/' AS URL,
6113 'Corruption check of ' + DB_NAME(db.resource_database_id) + ' database (' + (SELECT CAST(CAST(SUM(size * 8.0 / 1024 / 1024) AS BIGINT) AS NVARCHAR) FROM sys.master_files WHERE database_id = db.resource_database_id) + 'GB) has been running since ' + CAST(r.start_time AS NVARCHAR(100)) + '. ' AS Details,
6114 'KILL ' + CAST(r.session_id AS NVARCHAR(100)) + ';' AS HowToStopIt,
6115 pl.query_plan AS QueryPlan,
6116 r.start_time AS StartTime,
6117 s.login_name AS LoginName,
6118 s.nt_user_name AS NTUserName,
6119 s.[program_name] AS ProgramName,
6120 s.[host_name] AS HostName,
6121 db.[resource_database_id] AS DatabaseID,
6122 DB_NAME(db.resource_database_id) AS DatabaseName,
6123 0 AS OpenTransactionCount
6124 FROM sys.dm_exec_requests r
6125 INNER JOIN sys.dm_exec_connections c ON r.session_id = c.session_id
6126 INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
6127 INNER JOIN (SELECT DISTINCT l.request_session_id, l.resource_database_id
6128 FROM sys.dm_tran_locks l
6129 INNER JOIN sys.databases d ON l.resource_database_id = d.database_id
6130 WHERE l.resource_type = N'DATABASE'
6131 AND l.request_mode = N'S'
6132 AND l.request_status = N'GRANT'
6133 AND l.request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
6134 CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
6135 WHERE r.command LIKE 'DBCC%';
6136
6137
6138 /* Maintenance Tasks Running - Restore Running - CheckID 3 */
6139 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
6140 SELECT 3 AS CheckID,
6141 1 AS Priority,
6142 'Maintenance Tasks Running' AS FindingGroup,
6143 'Restore Running' AS Finding,
6144 'http://BrentOzar.com/askbrent/backups/' AS URL,
6145 'Restore of ' + DB_NAME(db.resource_database_id) + ' database (' + (SELECT CAST(CAST(SUM(size * 8.0 / 1024 / 1024) AS BIGINT) AS NVARCHAR) FROM sys.master_files WHERE database_id = db.resource_database_id) + 'GB) is ' + CAST(r.percent_complete AS NVARCHAR(100)) + '% complete, has been running since ' + CAST(r.start_time AS NVARCHAR(100)) + '. ' AS Details,
6146 'KILL ' + CAST(r.session_id AS NVARCHAR(100)) + ';' AS HowToStopIt,
6147 pl.query_plan AS QueryPlan,
6148 r.start_time AS StartTime,
6149 s.login_name AS LoginName,
6150 s.nt_user_name AS NTUserName,
6151 s.[program_name] AS ProgramName,
6152 s.[host_name] AS HostName,
6153 db.[resource_database_id] AS DatabaseID,
6154 DB_NAME(db.resource_database_id) AS DatabaseName,
6155 0 AS OpenTransactionCount
6156 FROM sys.dm_exec_requests r
6157 INNER JOIN sys.dm_exec_connections c ON r.session_id = c.session_id
6158 INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
6159 INNER JOIN (
6160 SELECT DISTINCT request_session_id, resource_database_id
6161 FROM sys.dm_tran_locks
6162 WHERE resource_type = N'DATABASE'
6163 AND request_mode = N'S'
6164 AND request_status = N'GRANT'
6165 AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
6166 CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
6167 WHERE r.command LIKE 'RESTORE%';
6168
6169
6170 /* SQL Server Internal Maintenance - Database File Growing - CheckID 4 */
6171 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
6172 SELECT 4 AS CheckID,
6173 1 AS Priority,
6174 'SQL Server Internal Maintenance' AS FindingGroup,
6175 'Database File Growing' AS Finding,
6176 'http://BrentOzar.com/go/instant' AS URL,
6177 'SQL Server is waiting for Windows to provide storage space for a database restore, a data file growth, or a log file growth. This task has been running since ' + CAST(r.start_time AS NVARCHAR(100)) + '.' + @LineFeed + 'Check the query plan (expert mode) to identify the database involved.' AS Details,
6178 'Unfortunately, you can''t stop this, but you can prevent it next time. Check out http://BrentOzar.com/go/instant for details.' AS HowToStopIt,
6179 pl.query_plan AS QueryPlan,
6180 r.start_time AS StartTime,
6181 s.login_name AS LoginName,
6182 s.nt_user_name AS NTUserName,
6183 s.[program_name] AS ProgramName,
6184 s.[host_name] AS HostName,
6185 NULL AS DatabaseID,
6186 NULL AS DatabaseName,
6187 0 AS OpenTransactionCount
6188 FROM sys.dm_os_waiting_tasks t
6189 INNER JOIN sys.dm_exec_connections c ON t.session_id = c.session_id
6190 INNER JOIN sys.dm_exec_requests r ON t.session_id = r.session_id
6191 INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
6192 CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
6193 WHERE t.wait_type = 'PREEMPTIVE_OS_WRITEFILEGATHER'
6194
6195
6196 /* Query Problems - Long-Running Query Blocking Others - CheckID 5 */
6197 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
6198 SELECT 5 AS CheckID,
6199 1 AS Priority,
6200 'Query Problems' AS FindingGroup,
6201 'Long-Running Query Blocking Others' AS Finding,
6202 'http://BrentOzar.com/go/blocking' AS URL,
6203 'Query in ' + DB_NAME(db.resource_database_id) + ' has been running since ' + CAST(r.start_time AS NVARCHAR(100)) + '. ' + @LineFeed + @LineFeed
6204 + CAST(COALESCE((SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(rBlocker.sql_handle)),
6205 (SELECT TOP 1 [text] FROM master..sysprocesses spBlocker CROSS APPLY ::fn_get_sql(spBlocker.sql_handle) WHERE spBlocker.spid = tBlocked.blocking_session_id), '') AS NVARCHAR(2000)) AS Details,
6206 'KILL ' + CAST(tBlocked.blocking_session_id AS NVARCHAR(100)) + ';' AS HowToStopIt,
6207 (SELECT TOP 1 query_plan FROM sys.dm_exec_query_plan(rBlocker.plan_handle)) AS QueryPlan,
6208 COALESCE((SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(rBlocker.sql_handle)),
6209 (SELECT TOP 1 [text] FROM master..sysprocesses spBlocker CROSS APPLY ::fn_get_sql(spBlocker.sql_handle) WHERE spBlocker.spid = tBlocked.blocking_session_id)) AS QueryText,
6210 r.start_time AS StartTime,
6211 s.login_name AS LoginName,
6212 s.nt_user_name AS NTUserName,
6213 s.[program_name] AS ProgramName,
6214 s.[host_name] AS HostName,
6215 db.[resource_database_id] AS DatabaseID,
6216 DB_NAME(db.resource_database_id) AS DatabaseName,
6217 0 AS OpenTransactionCount
6218 FROM sys.dm_exec_sessions s
6219 INNER JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
6220 INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
6221 INNER JOIN sys.dm_os_waiting_tasks tBlocked ON tBlocked.session_id = s.session_id AND tBlocked.session_id <> s.session_id
6222 INNER JOIN (
6223 SELECT DISTINCT request_session_id, resource_database_id
6224 FROM sys.dm_tran_locks
6225 WHERE resource_type = N'DATABASE'
6226 AND request_mode = N'S'
6227 AND request_status = N'GRANT'
6228 AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
6229 LEFT OUTER JOIN sys.dm_exec_requests rBlocker ON tBlocked.blocking_session_id = rBlocker.session_id
6230 WHERE NOT EXISTS (SELECT * FROM sys.dm_os_waiting_tasks tBlocker WHERE tBlocker.session_id = tBlocked.blocking_session_id AND tBlocker.blocking_session_id IS NOT NULL)
6231 AND s.last_request_start_time < DATEADD(SECOND, -30, GETDATE())
6232
6233 /* Query Problems - Plan Cache Erased Recently */
6234 IF DATEADD(mi, -15, GETDATE()) < (SELECT TOP 1 creation_time FROM sys.dm_exec_query_stats ORDER BY creation_time)
6235 BEGIN
6236 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
6237 SELECT TOP 1 7 AS CheckID,
6238 50 AS Priority,
6239 'Query Problems' AS FindingGroup,
6240 'Plan Cache Erased Recently' AS Finding,
6241 'http://BrentOzar.com/askbrent/plan-cache-erased-recently/' AS URL,
6242 'The oldest query in the plan cache was created at ' + CAST(creation_time AS NVARCHAR(50)) + '. ' + @LineFeed + @LineFeed
6243 + 'This indicates that someone ran DBCC FREEPROCCACHE at that time,' + @LineFeed
6244 + 'Giving SQL Server temporary amnesia. Now, as queries come in,' + @LineFeed
6245 + 'SQL Server has to use a lot of CPU power in order to build execution' + @LineFeed
6246 + 'plans and put them in cache again. This causes high CPU loads.' AS Details,
6247 'Find who did that, and stop them from doing it again.' AS HowToStopIt
6248 FROM sys.dm_exec_query_stats
6249 ORDER BY creation_time
6250 END;
6251
6252
6253 /* Query Problems - Sleeping Query with Open Transactions - CheckID 8 */
6254 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, QueryText, OpenTransactionCount)
6255 SELECT 8 AS CheckID,
6256 50 AS Priority,
6257 'Query Problems' AS FindingGroup,
6258 'Sleeping Query with Open Transactions' AS Finding,
6259 'http://www.brentozar.com/askbrent/sleeping-query-with-open-transactions/' AS URL,
6260 'Database: ' + DB_NAME(db.resource_database_id) + @LineFeed + 'Host: ' + s.[host_name] + @LineFeed + 'Program: ' + s.[program_name] + @LineFeed + 'Asleep with open transactions and locks since ' + CAST(s.last_request_end_time AS NVARCHAR(100)) + '. ' AS Details,
6261 'KILL ' + CAST(s.session_id AS NVARCHAR(100)) + ';' AS HowToStopIt,
6262 s.last_request_start_time AS StartTime,
6263 s.login_name AS LoginName,
6264 s.nt_user_name AS NTUserName,
6265 s.[program_name] AS ProgramName,
6266 s.[host_name] AS HostName,
6267 db.[resource_database_id] AS DatabaseID,
6268 DB_NAME(db.resource_database_id) AS DatabaseName,
6269 (SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(c.most_recent_sql_handle)) AS QueryText,
6270 sessions_with_transactions.open_transaction_count AS OpenTransactionCount
6271 FROM (SELECT session_id, SUM(open_transaction_count) AS open_transaction_count FROM sys.dm_exec_requests WHERE open_transaction_count > 0 GROUP BY session_id) AS sessions_with_transactions
6272 INNER JOIN sys.dm_exec_sessions s ON sessions_with_transactions.session_id = s.session_id
6273 INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
6274 INNER JOIN (
6275 SELECT DISTINCT request_session_id, resource_database_id
6276 FROM sys.dm_tran_locks
6277 WHERE resource_type = N'DATABASE'
6278 AND request_mode = N'S'
6279 AND request_status = N'GRANT'
6280 AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
6281 WHERE s.status = 'sleeping'
6282 AND s.last_request_end_time < DATEADD(ss, -10, GETDATE())
6283 AND EXISTS(SELECT * FROM sys.dm_tran_locks WHERE request_session_id = s.session_id
6284 AND NOT (resource_type = N'DATABASE' AND request_mode = N'S' AND request_status = N'GRANT' AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE'))
6285
6286
6287 /* Query Problems - Query Rolling Back - CheckID 9 */
6288 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, QueryText)
6289 SELECT 9 AS CheckID,
6290 1 AS Priority,
6291 'Query Problems' AS FindingGroup,
6292 'Query Rolling Back' AS Finding,
6293 'http://BrentOzar.com/askbrent/rollback/' AS URL,
6294 'Rollback started at ' + CAST(r.start_time AS NVARCHAR(100)) + ', is ' + CAST(r.percent_complete AS NVARCHAR(100)) + '% complete.' AS Details,
6295 'Unfortunately, you can''t stop this. Whatever you do, don''t restart the server in an attempt to fix it - SQL Server will keep rolling back.' AS HowToStopIt,
6296 r.start_time AS StartTime,
6297 s.login_name AS LoginName,
6298 s.nt_user_name AS NTUserName,
6299 s.[program_name] AS ProgramName,
6300 s.[host_name] AS HostName,
6301 db.[resource_database_id] AS DatabaseID,
6302 DB_NAME(db.resource_database_id) AS DatabaseName,
6303 (SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(c.most_recent_sql_handle)) AS QueryText
6304 FROM sys.dm_exec_sessions s
6305 INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
6306 INNER JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
6307 LEFT OUTER JOIN (
6308 SELECT DISTINCT request_session_id, resource_database_id
6309 FROM sys.dm_tran_locks
6310 WHERE resource_type = N'DATABASE'
6311 AND request_mode = N'S'
6312 AND request_status = N'GRANT'
6313 AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
6314 WHERE r.status = 'rollback'
6315
6316
6317 /* Server Performance - Page Life Expectancy Low - CheckID 10 */
6318 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
6319 SELECT 10 AS CheckID,
6320 50 AS Priority,
6321 'Server Performance' AS FindingGroup,
6322 'Page Life Expectancy Low' AS Finding,
6323 'http://BrentOzar.com/askbrent/page-life-expectancy/' AS URL,
6324 'SQL Server Buffer Manager:Page life expectancy is ' + CAST(c.cntr_value AS NVARCHAR(10)) + ' seconds.' + @LineFeed
6325 + 'This means SQL Server can only keep data pages in memory for that many seconds after reading those pages in from storage.' + @LineFeed
6326 + 'This is a symptom, not a cause - it indicates very read-intensive queries that need an index, or insufficient server memory.' AS Details,
6327 'Add more memory to the server, or find the queries reading a lot of data, and make them more efficient (or fix them with indexes).' AS HowToStopIt
6328 FROM sys.dm_os_performance_counters c
6329 WHERE object_name LIKE 'SQLServer:Buffer Manager%'
6330 AND counter_name LIKE 'Page life expectancy%'
6331 AND cntr_value < 300
6332
6333
6334
6335 /* End of checks. If we haven't waited @Seconds seconds, wait. */
6336 IF GETDATE() < @FinishSampleTime
6337 WAITFOR TIME @FinishSampleTime;
6338
6339
6340 /* Populate #FileStats, #PerfmonStats, #WaitStats with DMV data. In a second, we'll compare these. */
6341 INSERT #WaitStats(Pass, SampleTime, wait_type, wait_time_ms, signal_wait_time_ms, waiting_tasks_count)
6342 SELECT
6343 2 AS Pass,
6344 GETDATE() AS SampleTime,
6345 os.wait_type,
6346 SUM(os.wait_time_ms) OVER (PARTITION BY os.wait_type) as sum_wait_time_ms,
6347 SUM(os.signal_wait_time_ms) OVER (PARTITION BY os.wait_type ) as sum_signal_wait_time_ms,
6348 SUM(os.waiting_tasks_count) OVER (PARTITION BY os.wait_type) AS sum_waiting_tasks
6349 FROM sys.dm_os_wait_stats os
6350 WHERE os.wait_type not in (
6351 'REQUEST_FOR_DEADLOCK_SEARCH',
6352 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
6353 'SQLTRACE_BUFFER_FLUSH',
6354 'LAZYWRITER_SLEEP',
6355 'XE_TIMER_EVENT',
6356 'XE_DISPATCHER_WAIT',
6357 'FT_IFTS_SCHEDULER_IDLE_WAIT',
6358 'LOGMGR_QUEUE',
6359 'CHECKPOINT_QUEUE',
6360 'BROKER_TO_FLUSH',
6361 'BROKER_TASK_STOP',
6362 'BROKER_EVENTHANDLER',
6363 'SLEEP_TASK',
6364 'WAITFOR',
6365 'DBMIRROR_DBM_MUTEX',
6366 'DBMIRROR_EVENTS_QUEUE',
6367 'DBMIRRORING_CMD',
6368 'DISPATCHER_QUEUE_SEMAPHORE',
6369 'BROKER_RECEIVE_WAITFOR',
6370 'CLR_AUTO_EVENT',
6371 'DIRTY_PAGE_POLL',
6372 'HADR_FILESTREAM_IOMGR_IOCOMPLETION',
6373 'ONDEMAND_TASK_QUEUE',
6374 'FT_IFTSHC_MUTEX',
6375 'CLR_MANUAL_EVENT',
6376 'CLR_SEMAPHORE',
6377 'DBMIRROR_WORKER_QUEUE',
6378 'DBMIRROR_DBM_EVENT',
6379 'SP_SERVER_DIAGNOSTICS_SLEEP',
6380 'HADR_CLUSAPI_CALL',
6381 'HADR_LOGCAPTURE_WAIT',
6382 'HADR_TIMER_TASK',
6383 'HADR_WORK_QUEUE',
6384 'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP',
6385 'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP'
6386 )
6387 ORDER BY sum_wait_time_ms DESC;
6388
6389 INSERT INTO #FileStats (Pass, SampleTime, DatabaseID, FileID, DatabaseName, FileLogicalName, SizeOnDiskMB, io_stall_read_ms ,
6390 num_of_reads, [bytes_read] , io_stall_write_ms,num_of_writes, [bytes_written], PhysicalName, TypeDesc, avg_stall_read_ms, avg_stall_write_ms)
6391 SELECT 2 AS Pass,
6392 GETDATE() AS SampleTime,
6393 mf.[database_id],
6394 mf.[file_id],
6395 DB_NAME(vfs.database_id) AS [db_name],
6396 mf.name + N' [' + mf.type_desc COLLATE SQL_Latin1_General_CP1_CI_AS + N']' AS file_logical_name ,
6397 CAST(( ( vfs.size_on_disk_bytes / 1024.0 ) / 1024.0 ) AS INT) AS size_on_disk_mb ,
6398 vfs.io_stall_read_ms ,
6399 vfs.num_of_reads ,
6400 vfs.[num_of_bytes_read],
6401 vfs.io_stall_write_ms ,
6402 vfs.num_of_writes ,
6403 vfs.[num_of_bytes_written],
6404 mf.physical_name,
6405 mf.type_desc,
6406 0,
6407 0
6408 FROM sys.dm_io_virtual_file_stats (NULL, NULL) AS vfs
6409 INNER JOIN sys.master_files AS mf ON vfs.file_id = mf.file_id
6410 AND vfs.database_id = mf.database_id
6411 WHERE vfs.num_of_reads > 0
6412 OR vfs.num_of_writes > 0;
6413
6414 INSERT INTO #PerfmonStats (Pass, SampleTime, [object_name],[counter_name],[instance_name],[cntr_value],[cntr_type])
6415 SELECT 2 AS Pass,
6416 GETDATE() AS SampleTime,
6417 RTRIM(dmv.object_name), RTRIM(dmv.counter_name), RTRIM(dmv.instance_name), dmv.cntr_value, dmv.cntr_type
6418 FROM #PerfmonCounters counters
6419 INNER JOIN sys.dm_os_performance_counters dmv ON counters.counter_name = RTRIM(dmv.counter_name)
6420 AND counters.[object_name] = RTRIM(dmv.[object_name])
6421 AND (counters.[instance_name] IS NULL OR counters.[instance_name] = RTRIM(dmv.[instance_name]))
6422
6423 /* Set the latencies and averages. We could do this with a CTE, but we're not ambitious today. */
6424 UPDATE fNow
6425 SET avg_stall_read_ms = ((fNow.io_stall_read_ms - fBase.io_stall_read_ms) / (fNow.num_of_reads - fBase.num_of_reads))
6426 FROM #FileStats fNow
6427 INNER JOIN #FileStats fBase ON fNow.DatabaseID = fBase.DatabaseID AND fNow.FileID = fBase.FileID AND fNow.SampleTime > fBase.SampleTime AND fNow.num_of_reads > fBase.num_of_reads AND fNow.io_stall_read_ms > fBase.io_stall_read_ms
6428 WHERE (fNow.num_of_reads - fBase.num_of_reads) > 0
6429
6430 UPDATE fNow
6431 SET avg_stall_write_ms = ((fNow.io_stall_write_ms - fBase.io_stall_write_ms) / (fNow.num_of_writes - fBase.num_of_writes))
6432 FROM #FileStats fNow
6433 INNER JOIN #FileStats fBase ON fNow.DatabaseID = fBase.DatabaseID AND fNow.FileID = fBase.FileID AND fNow.SampleTime > fBase.SampleTime AND fNow.num_of_writes > fBase.num_of_writes AND fNow.io_stall_write_ms > fBase.io_stall_write_ms
6434 WHERE (fNow.num_of_writes - fBase.num_of_writes) > 0
6435
6436 UPDATE pNow
6437 SET [value_delta] = pNow.cntr_value - pFirst.cntr_value,
6438 [value_per_second] = ((1.0 * pNow.cntr_value - pFirst.cntr_value) / DATEDIFF(ss, pFirst.SampleTime, pNow.SampleTime))
6439 FROM #PerfmonStats pNow
6440 INNER JOIN #PerfmonStats pFirst ON pFirst.[object_name] = pNow.[object_name] AND pFirst.counter_name = pNow.counter_name AND (pFirst.instance_name = pNow.instance_name OR (pFirst.instance_name IS NULL AND pNow.instance_name IS NULL))
6441 AND pNow.ID > pFirst.ID;
6442
6443
6444 /* If we're within 10 seconds of our projected finish time, do the plan cache analysis. */
6445 IF DATEDIFF(ss, @FinishSampleTime, GETDATE()) > 10 AND @ExpertMode = 0
6446 BEGIN
6447
6448 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
6449 VALUES (18, 210, 'Query Stats', 'Plan Cache Analysis Skipped', 'http://BrentOzar.com/go/topqueries',
6450 'Due to excessive load, the plan cache analysis was skipped. To override this, use @ExpertMode = 1.')
6451
6452 END
6453 ELSE /* IF DATEDIFF(ss, @FinishSampleTime, GETDATE()) > 10 AND @ExpertMode = 0 */
6454 BEGIN
6455
6456
6457 /* Populate #QueryStats. SQL 2005 doesn't have query hash or query plan hash. */
6458 IF @@VERSION LIKE 'Microsoft SQL Server 2005%'
6459 SET @StringToExecute = N'INSERT INTO #QueryStats ([sql_handle], Pass, SampleTime, statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, query_hash, query_plan_hash, Points)
6460 SELECT [sql_handle], 2 AS Pass, GETDATE(), statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, NULL AS query_hash, NULL AS query_plan_hash, 0
6461 FROM sys.dm_exec_query_stats qs
6462 WHERE qs.last_execution_time >= ''' + CAST(@StartSampleTime AS NVARCHAR(100)) + ''';';
6463 ELSE
6464 SET @StringToExecute = N'INSERT INTO #QueryStats ([sql_handle], Pass, SampleTime, statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, query_hash, query_plan_hash, Points)
6465 SELECT [sql_handle], 2 AS Pass, GETDATE(), statement_start_offset, statement_end_offset, plan_generation_num, plan_handle, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time, query_hash, query_plan_hash, 0
6466 FROM sys.dm_exec_query_stats qs
6467 WHERE qs.last_execution_time >= ''' + CAST(@StartSampleTime AS NVARCHAR(100)) + ''';';
6468 EXEC(@StringToExecute);
6469
6470 /* Get the totals for the entire plan cache */
6471 INSERT INTO #QueryStats (Pass, SampleTime, execution_count, total_worker_time, total_physical_reads, total_logical_writes, total_logical_reads, total_clr_time, total_elapsed_time, creation_time)
6472 SELECT 0 AS Pass, GETDATE(), SUM(execution_count), SUM(total_worker_time), SUM(total_physical_reads), SUM(total_logical_writes), SUM(total_logical_reads), SUM(total_clr_time), SUM(total_elapsed_time), MIN(creation_time)
6473 FROM sys.dm_exec_query_stats qs;
6474
6475 /*
6476 Pick the most resource-intensive queries to review. Update the Points field
6477 in #QueryStats - if a query is in the top 10 for logical reads, CPU time,
6478 duration, or execution, add 1 to its points.
6479 */
6480 WITH qsTop AS (
6481 SELECT TOP 10 qsNow.ID
6482 FROM #QueryStats qsNow
6483 INNER JOIN #QueryStats qsFirst ON qsNow.[sql_handle] = qsFirst.[sql_handle] AND qsNow.statement_start_offset = qsFirst.statement_start_offset AND qsNow.statement_end_offset = qsFirst.statement_end_offset AND qsNow.plan_generation_num = qsFirst.plan_generation_num AND qsNow.plan_handle = qsFirst.plan_handle AND qsFirst.Pass = 1
6484 WHERE qsNow.total_elapsed_time > qsFirst.total_elapsed_time
6485 AND qsNow.Pass = 2
6486 AND qsNow.total_elapsed_time - qsFirst.total_elapsed_time > 1000000 /* Only queries with over 1 second of runtime */
6487 ORDER BY (qsNow.total_elapsed_time - COALESCE(qsFirst.total_elapsed_time, 0)) DESC)
6488 UPDATE #QueryStats
6489 SET Points = Points + 1
6490 FROM #QueryStats qs
6491 INNER JOIN qsTop ON qs.ID = qsTop.ID;
6492
6493 WITH qsTop AS (
6494 SELECT TOP 10 qsNow.ID
6495 FROM #QueryStats qsNow
6496 INNER JOIN #QueryStats qsFirst ON qsNow.[sql_handle] = qsFirst.[sql_handle] AND qsNow.statement_start_offset = qsFirst.statement_start_offset AND qsNow.statement_end_offset = qsFirst.statement_end_offset AND qsNow.plan_generation_num = qsFirst.plan_generation_num AND qsNow.plan_handle = qsFirst.plan_handle AND qsFirst.Pass = 1
6497 WHERE qsNow.total_logical_reads > qsFirst.total_logical_reads
6498 AND qsNow.Pass = 2
6499 AND qsNow.total_logical_reads - qsFirst.total_logical_reads > 1000 /* Only queries with over 1000 reads */
6500 ORDER BY (qsNow.total_logical_reads - COALESCE(qsFirst.total_logical_reads, 0)) DESC)
6501 UPDATE #QueryStats
6502 SET Points = Points + 1
6503 FROM #QueryStats qs
6504 INNER JOIN qsTop ON qs.ID = qsTop.ID;
6505
6506 WITH qsTop AS (
6507 SELECT TOP 10 qsNow.ID
6508 FROM #QueryStats qsNow
6509 INNER JOIN #QueryStats qsFirst ON qsNow.[sql_handle] = qsFirst.[sql_handle] AND qsNow.statement_start_offset = qsFirst.statement_start_offset AND qsNow.statement_end_offset = qsFirst.statement_end_offset AND qsNow.plan_generation_num = qsFirst.plan_generation_num AND qsNow.plan_handle = qsFirst.plan_handle AND qsFirst.Pass = 1
6510 WHERE qsNow.total_worker_time > qsFirst.total_worker_time
6511 AND qsNow.Pass = 2
6512 AND qsNow.total_worker_time - qsFirst.total_worker_time > 1000000 /* Only queries with over 1 second of worker time */
6513 ORDER BY (qsNow.total_worker_time - COALESCE(qsFirst.total_worker_time, 0)) DESC)
6514 UPDATE #QueryStats
6515 SET Points = Points + 1
6516 FROM #QueryStats qs
6517 INNER JOIN qsTop ON qs.ID = qsTop.ID;
6518
6519 WITH qsTop AS (
6520 SELECT TOP 10 qsNow.ID
6521 FROM #QueryStats qsNow
6522 INNER JOIN #QueryStats qsFirst ON qsNow.[sql_handle] = qsFirst.[sql_handle] AND qsNow.statement_start_offset = qsFirst.statement_start_offset AND qsNow.statement_end_offset = qsFirst.statement_end_offset AND qsNow.plan_generation_num = qsFirst.plan_generation_num AND qsNow.plan_handle = qsFirst.plan_handle AND qsFirst.Pass = 1
6523 WHERE qsNow.execution_count > qsFirst.execution_count
6524 AND qsNow.Pass = 2
6525 AND (qsNow.total_elapsed_time - qsFirst.total_elapsed_time > 1000000 /* Only queries with over 1 second of runtime */
6526 OR qsNow.total_logical_reads - qsFirst.total_logical_reads > 1000 /* Only queries with over 1000 reads */
6527 OR qsNow.total_worker_time - qsFirst.total_worker_time > 1000000 /* Only queries with over 1 second of worker time */)
6528 ORDER BY (qsNow.execution_count - COALESCE(qsFirst.execution_count, 0)) DESC)
6529 UPDATE #QueryStats
6530 SET Points = Points + 1
6531 FROM #QueryStats qs
6532 INNER JOIN qsTop ON qs.ID = qsTop.ID;
6533
6534 /* Query Stats - CheckID 17 - Most Resource-Intensive Queries */
6535 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, QueryStatsNowID, QueryStatsFirstID, PlanHandle)
6536 SELECT 17, 210, 'Query Stats', 'Most Resource-Intensive Queries', 'http://BrentOzar.com/go/topqueries',
6537 'Query stats during the sample:' + @LineFeed +
6538 'Executions: ' + CAST(qsNow.execution_count - (COALESCE(qsFirst.execution_count, 0)) AS NVARCHAR(100)) + @LineFeed +
6539 'Elapsed Time: ' + CAST(qsNow.total_elapsed_time - (COALESCE(qsFirst.total_elapsed_time, 0)) AS NVARCHAR(100)) + @LineFeed +
6540 'CPU Time: ' + CAST(qsNow.total_worker_time - (COALESCE(qsFirst.total_worker_time, 0)) AS NVARCHAR(100)) + @LineFeed +
6541 'Logical Reads: ' + CAST(qsNow.total_logical_reads - (COALESCE(qsFirst.total_logical_reads, 0)) AS NVARCHAR(100)) + @LineFeed +
6542 'Logical Writes: ' + CAST(qsNow.total_logical_writes - (COALESCE(qsFirst.total_logical_writes, 0)) AS NVARCHAR(100)) + @LineFeed +
6543 'CLR Time: ' + CAST(qsNow.total_clr_time - (COALESCE(qsFirst.total_clr_time, 0)) AS NVARCHAR(100)) + @LineFeed +
6544 @LineFeed + @LineFeed + 'Query stats since ' + CONVERT(NVARCHAR(100), qsNow.creation_time ,121) + @LineFeed +
6545 'Executions: ' + CAST(qsNow.execution_count AS NVARCHAR(100)) +
6546 CASE qsTotal.execution_count WHEN 0 THEN '' ELSE (' - Percent of Server Total: ' + CAST(CAST(100.0 * qsNow.execution_count / qsTotal.execution_count AS DECIMAL(6,2)) AS NVARCHAR(100)) + '%') END + @LineFeed +
6547 'Elapsed Time: ' + CAST(qsNow.total_elapsed_time AS NVARCHAR(100)) +
6548 CASE qsTotal.total_elapsed_time WHEN 0 THEN '' ELSE (' - Percent of Server Total: ' + CAST(CAST(100.0 * qsNow.total_elapsed_time / qsTotal.total_elapsed_time AS DECIMAL(6,2)) AS NVARCHAR(100)) + '%') END + @LineFeed +
6549 'CPU Time: ' + CAST(qsNow.total_worker_time AS NVARCHAR(100)) +
6550 CASE qsTotal.total_worker_time WHEN 0 THEN '' ELSE (' - Percent of Server Total: ' + CAST(CAST(100.0 * qsNow.total_worker_time / qsTotal.total_worker_time AS DECIMAL(6,2)) AS NVARCHAR(100)) + '%') END + @LineFeed +
6551 'Logical Reads: ' + CAST(qsNow.total_logical_reads AS NVARCHAR(100)) +
6552 CASE qsTotal.total_logical_reads WHEN 0 THEN '' ELSE (' - Percent of Server Total: ' + CAST(CAST(100.0 * qsNow.total_logical_reads / qsTotal.total_logical_reads AS DECIMAL(6,2)) AS NVARCHAR(100)) + '%') END + @LineFeed +
6553 'Logical Writes: ' + CAST(qsNow.total_logical_writes AS NVARCHAR(100)) +
6554 CASE qsTotal.total_logical_writes WHEN 0 THEN '' ELSE (' - Percent of Server Total: ' + CAST(CAST(100.0 * qsNow.total_logical_writes / qsTotal.total_logical_writes AS DECIMAL(6,2)) AS NVARCHAR(100)) + '%') END + @LineFeed +
6555 'CLR Time: ' + CAST(qsNow.total_clr_time AS NVARCHAR(100)) +
6556 CASE qsTotal.total_clr_time WHEN 0 THEN '' ELSE (' - Percent of Server Total: ' + CAST(CAST(100.0 * qsNow.total_clr_time / qsTotal.total_clr_time AS DECIMAL(6,2)) AS NVARCHAR(100)) + '%') END + @LineFeed +
6557 --@LineFeed + @LineFeed + 'Query hash: ' + CAST(qsNow.query_hash AS NVARCHAR(100)) + @LineFeed +
6558 --@LineFeed + @LineFeed + 'Query plan hash: ' + CAST(qsNow.query_plan_hash AS NVARCHAR(100)) +
6559 @LineFeed AS Details,
6560 'See the URL for tuning tips on why this query may be consuming resources.' AS HowToStopIt,
6561 qp.query_plan,
6562 QueryText = SUBSTRING(st.text,
6563 (qsNow.statement_start_offset / 2) + 1,
6564 ((CASE qsNow.statement_end_offset
6565 WHEN -1 THEN DATALENGTH(st.text)
6566 ELSE qsNow.statement_end_offset
6567 END - qsNow.statement_start_offset) / 2) + 1),
6568 qsNow.ID AS QueryStatsNowID,
6569 qsFirst.ID AS QueryStatsFirstID,
6570 qsNow.plan_handle AS PlanHandle
6571 FROM #QueryStats qsNow
6572 INNER JOIN #QueryStats qsTotal ON qsTotal.Pass = 0
6573 LEFT OUTER JOIN #QueryStats qsFirst ON qsNow.[sql_handle] = qsFirst.[sql_handle] AND qsNow.statement_start_offset = qsFirst.statement_start_offset AND qsNow.statement_end_offset = qsFirst.statement_end_offset AND qsNow.plan_generation_num = qsFirst.plan_generation_num AND qsNow.plan_handle = qsFirst.plan_handle AND qsFirst.Pass = 1
6574 CROSS APPLY sys.dm_exec_sql_text(qsNow.sql_handle) AS st
6575 CROSS APPLY sys.dm_exec_query_plan(qsNow.plan_handle) AS qp
6576 WHERE qsNow.Points > 0 AND st.text IS NOT NULL AND qp.query_plan IS NOT NULL
6577
6578 UPDATE #AskBrentResults
6579 SET DatabaseID = CAST(attr.value AS INT),
6580 DatabaseName = DB_NAME(CAST(attr.value AS INT))
6581 FROM #AskBrentResults
6582 CROSS APPLY sys.dm_exec_plan_attributes(#AskBrentResults.PlanHandle) AS attr
6583 WHERE attr.attribute = 'dbid'
6584
6585
6586 END /* IF DATEDIFF(ss, @FinishSampleTime, GETDATE()) > 10 AND @ExpertMode = 0 */
6587
6588
6589 /* Wait Stats - CheckID 6 */
6590 /* Compare the current wait stats to the sample we took at the start, and insert the top 10 waits. */
6591 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
6592 SELECT TOP 10 6 AS CheckID,
6593 200 AS Priority,
6594 'Wait Stats' AS FindingGroup,
6595 wNow.wait_type AS Finding,
6596 N'http://www.brentozar.com/sql/wait-stats/#' + wNow.wait_type AS URL,
6597 'For ' + CAST(((wNow.wait_time_ms - COALESCE(wBase.wait_time_ms,0)) / 1000) AS NVARCHAR(100)) + ' seconds over the last ' + CAST(@Seconds AS NVARCHAR(10)) + ' seconds, SQL Server was waiting on this particular bottleneck.' + @LineFeed + @LineFeed AS Details,
6598 'See the URL for more details on how to mitigate this wait type.' AS HowToStopIt
6599 FROM #WaitStats wNow
6600 LEFT OUTER JOIN #WaitStats wBase ON wNow.wait_type = wBase.wait_type AND wNow.SampleTime > wBase.SampleTime
6601 WHERE wNow.wait_time_ms > (wBase.wait_time_ms + (.5 * @Seconds * 1000)) /* Only look for things we've actually waited on for half of the time or more */
6602 ORDER BY (wNow.wait_time_ms - COALESCE(wBase.wait_time_ms,0)) DESC;
6603
6604 /* Server Performance - Slow Data File Reads - CheckID 11 */
6605 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, DatabaseID, DatabaseName)
6606 SELECT TOP 10 11 AS CheckID,
6607 50 AS Priority,
6608 'Server Performance' AS FindingGroup,
6609 'Slow Data File Reads' AS Finding,
6610 'http://BrentOzar.com/go/slow/' AS URL,
6611 'File: ' + fNow.PhysicalName + @LineFeed
6612 + 'Number of reads during the sample: ' + CAST((fNow.num_of_reads - fBase.num_of_reads) AS NVARCHAR(20)) + @LineFeed
6613 + 'Seconds spent waiting on storage for these reads: ' + CAST(((fNow.io_stall_read_ms - fBase.io_stall_read_ms) / 1000.0) AS NVARCHAR(20)) + @LineFeed
6614 + 'Average read latency during the sample: ' + CAST(((fNow.io_stall_read_ms - fBase.io_stall_read_ms) / (fNow.num_of_reads - fBase.num_of_reads) ) AS NVARCHAR(20)) + ' milliseconds' + @LineFeed
6615 + 'Microsoft guidance for data file read speed: 20ms or less.' + @LineFeed + @LineFeed AS Details,
6616 'See the URL for more details on how to mitigate this wait type.' AS HowToStopIt,
6617 fNow.DatabaseID,
6618 fNow.DatabaseName
6619 FROM #FileStats fNow
6620 INNER JOIN #FileStats fBase ON fNow.DatabaseID = fBase.DatabaseID AND fNow.FileID = fBase.FileID AND fNow.SampleTime > fBase.SampleTime AND fNow.num_of_reads > fBase.num_of_reads AND fNow.io_stall_read_ms > (fBase.io_stall_read_ms + 1000)
6621 WHERE (fNow.io_stall_read_ms - fBase.io_stall_read_ms) / (fNow.num_of_reads - fBase.num_of_reads) > 100
6622 AND fNow.TypeDesc = 'ROWS'
6623 ORDER BY (fNow.io_stall_read_ms - fBase.io_stall_read_ms) / (fNow.num_of_reads - fBase.num_of_reads) DESC;
6624
6625 /* Server Performance - Slow Log File Writes - CheckID 12 */
6626 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, DatabaseID, DatabaseName)
6627 SELECT TOP 10 12 AS CheckID,
6628 50 AS Priority,
6629 'Server Performance' AS FindingGroup,
6630 'Slow Log File Writes' AS Finding,
6631 'http://BrentOzar.com/go/slow/' AS URL,
6632 'File: ' + fNow.PhysicalName + @LineFeed
6633 + 'Number of writes during the sample: ' + CAST((fNow.num_of_writes - fBase.num_of_writes) AS NVARCHAR(20)) + @LineFeed
6634 + 'Seconds spent waiting on storage for these writes: ' + CAST(((fNow.io_stall_write_ms - fBase.io_stall_write_ms) / 1000.0) AS NVARCHAR(20)) + @LineFeed
6635 + 'Average write latency during the sample: ' + CAST(((fNow.io_stall_write_ms - fBase.io_stall_write_ms) / (fNow.num_of_writes - fBase.num_of_writes) ) AS NVARCHAR(20)) + ' milliseconds' + @LineFeed
6636 + 'Microsoft guidance for log file write speed: 3ms or less.' + @LineFeed + @LineFeed AS Details,
6637 'See the URL for more details on how to mitigate this wait type.' AS HowToStopIt,
6638 fNow.DatabaseID,
6639 fNow.DatabaseName
6640 FROM #FileStats fNow
6641 INNER JOIN #FileStats fBase ON fNow.DatabaseID = fBase.DatabaseID AND fNow.FileID = fBase.FileID AND fNow.SampleTime > fBase.SampleTime AND fNow.num_of_writes > fBase.num_of_writes AND fNow.io_stall_write_ms > (fBase.io_stall_write_ms + 1000)
6642 WHERE (fNow.io_stall_write_ms - fBase.io_stall_write_ms) / (fNow.num_of_writes - fBase.num_of_writes) > 100
6643 AND fNow.TypeDesc = 'LOG'
6644 ORDER BY (fNow.io_stall_write_ms - fBase.io_stall_write_ms) / (fNow.num_of_writes - fBase.num_of_writes) DESC;
6645
6646
6647 /* SQL Server Internal Maintenance - Log File Growing - CheckID 13 */
6648 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
6649 SELECT 13 AS CheckID,
6650 1 AS Priority,
6651 'SQL Server Internal Maintenance' AS FindingGroup,
6652 'Log File Growing' AS Finding,
6653 'http://BrentOzar.com/askbrent/file-growing/' AS URL,
6654 'Number of growths during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
6655 + 'Determined by sampling Perfmon counter ' + ps.object_name + ' - ' + ps.counter_name + @LineFeed AS Details,
6656 'Pre-grow data and log files during maintenance windows so that they do not grow during production loads. See the URL for more details.' AS HowToStopIt
6657 FROM #PerfmonStats ps
6658 WHERE ps.Pass = 2
6659 AND object_name = 'SQLServer:Databases'
6660 AND counter_name = 'Log Growths'
6661 AND value_delta > 0
6662
6663
6664 /* SQL Server Internal Maintenance - Log File Shrinking - CheckID 14 */
6665 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
6666 SELECT 14 AS CheckID,
6667 1 AS Priority,
6668 'SQL Server Internal Maintenance' AS FindingGroup,
6669 'Log File Shrinking' AS Finding,
6670 'http://BrentOzar.com/askbrent/file-shrinking/' AS URL,
6671 'Number of shrinks during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
6672 + 'Determined by sampling Perfmon counter ' + ps.object_name + ' - ' + ps.counter_name + @LineFeed AS Details,
6673 'Pre-grow data and log files during maintenance windows so that they do not grow during production loads. See the URL for more details.' AS HowToStopIt
6674 FROM #PerfmonStats ps
6675 WHERE ps.Pass = 2
6676 AND object_name = 'SQLServer:Databases'
6677 AND counter_name = 'Log Shrinks'
6678 AND value_delta > 0
6679
6680 /* Query Problems - Compilations/Sec High - CheckID 15 */
6681 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
6682 SELECT 15 AS CheckID,
6683 50 AS Priority,
6684 'Query Problems' AS FindingGroup,
6685 'Compilations/Sec High' AS Finding,
6686 'http://BrentOzar.com/askbrent/compilations/' AS URL,
6687 'Number of batch requests during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
6688 + 'Number of compilations during the sample: ' + CAST(psComp.value_delta AS NVARCHAR(20)) + @LineFeed
6689 + 'For OLTP environments, Microsoft recommends that 90% of batch requests should hit the plan cache, and not be compiled from scratch. We are exceeding that threshold.' + @LineFeed AS Details,
6690 'Find out why plans are not being reused, and consider enabling Forced Parameterization. See the URL for more details.' AS HowToStopIt
6691 FROM #PerfmonStats ps
6692 INNER JOIN #PerfmonStats psComp ON psComp.Pass = 2 AND psComp.object_name = 'SQLServer:SQL Statistics' AND psComp.counter_name = 'SQL Compilations/sec' AND psComp.value_delta > 0
6693 WHERE ps.Pass = 2
6694 AND ps.object_name = 'SQLServer:SQL Statistics'
6695 AND ps.counter_name = 'Batch Requests/sec'
6696 AND ps.value_delta > (1000 * @Seconds) /* Ignore servers sitting idle */
6697 AND (psComp.value_delta * 10) > ps.value_delta /* Compilations are more than 10% of batch requests per second */
6698
6699 /* Query Problems - Re-Compilations/Sec High - CheckID 16 */
6700 INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
6701 SELECT 16 AS CheckID,
6702 50 AS Priority,
6703 'Query Problems' AS FindingGroup,
6704 'Re-Compilations/Sec High' AS Finding,
6705 'http://BrentOzar.com/askbrent/recompilations/' AS URL,
6706 'Number of batch requests during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
6707 + 'Number of recompilations during the sample: ' + CAST(psComp.value_delta AS NVARCHAR(20)) + @LineFeed
6708 + 'More than 10% of our queries are being recompiled. This is typically due to statistics changing on objects.' + @LineFeed AS Details,
6709 'Find out which objects are changing so quickly that they hit the stats update threshold. See the URL for more details.' AS HowToStopIt
6710 FROM #PerfmonStats ps
6711 INNER JOIN #PerfmonStats psComp ON psComp.Pass = 2 AND psComp.object_name = 'SQLServer:SQL Statistics' AND psComp.counter_name = 'SQL Re-Compilations/sec' AND psComp.value_delta > 0
6712 WHERE ps.Pass = 2
6713 AND ps.object_name = 'SQLServer:SQL Statistics'
6714 AND ps.counter_name = 'Batch Requests/sec'
6715 AND ps.value_delta > (1000 * @Seconds) /* Ignore servers sitting idle */
6716 AND (psComp.value_delta * 10) > ps.value_delta /* Recompilations are more than 10% of batch requests per second */
6717
6718
6719 /* If we didn't find anything, apologize. */
6720 IF NOT EXISTS (SELECT * FROM #AskBrentResults)
6721 BEGIN
6722
6723 INSERT INTO #AskBrentResults
6724 ( CheckID ,
6725 Priority ,
6726 FindingsGroup ,
6727 Finding ,
6728 URL ,
6729 Details
6730 )
6731 VALUES ( -1 ,
6732 255 ,
6733 'No Problems Found' ,
6734 'From Brent Ozar Unlimited' ,
6735 'http://www.BrentOzar.com/askbrent/' ,
6736 'Try running our more in-depth checks: http://www.BrentOzar.com/blitz/' + @LineFeed + 'or there may not be an unusual SQL Server performance problem. '
6737 );
6738
6739 END /*IF NOT EXISTS (SELECT * FROM #AskBrentResults) */
6740 ELSE /* We found stuff, so add credits */
6741 BEGIN
6742
6743 /* Add credits for the nice folks who put so much time into building and maintaining this for free: */
6744 INSERT INTO #AskBrentResults
6745 ( CheckID ,
6746 Priority ,
6747 FindingsGroup ,
6748 Finding ,
6749 URL ,
6750 Details
6751 )
6752 VALUES ( -1 ,
6753 255 ,
6754 'Thanks!' ,
6755 'From Brent Ozar Unlimited' ,
6756 'http://www.BrentOzar.com/askbrent/' ,
6757 'Thanks from the Brent Ozar Unlimited team. We hope you found this tool useful, and if you need help relieving your SQL Server pains, email us at Help@BrentOzar.com. '
6758 );
6759
6760 INSERT INTO #AskBrentResults
6761 ( CheckID ,
6762 Priority ,
6763 FindingsGroup ,
6764 Finding ,
6765 URL ,
6766 Details
6767
6768 )
6769 VALUES ( -1 ,
6770 0 ,
6771 'sp_AskBrent (TM) v' + CAST(@Version AS VARCHAR(20)) + ' as of ' + CAST(CONVERT(DATETIME, @VersionDate, 102) AS VARCHAR(100)),
6772 'From Brent Ozar Unlimited' ,
6773 'http://www.BrentOzar.com/askbrent/' ,
6774 'Thanks from the Brent Ozar Unlimited team. We hope you found this tool useful, and if you need help relieving your SQL Server pains, email us at Help@BrentOzar.com.'
6775 );
6776
6777 END /* ELSE We found stuff, so add credits */
6778
6779 /* @OutputTableName lets us export the results to a permanent table */
6780 IF @OutputDatabaseName IS NOT NULL
6781 AND @OutputSchemaName IS NOT NULL
6782 AND @OutputTableName IS NOT NULL
6783 AND EXISTS ( SELECT *
6784 FROM sys.databases
6785 WHERE QUOTENAME([name]) = @OutputDatabaseName)
6786 BEGIN
6787 SET @StringToExecute = 'USE '
6788 + @OutputDatabaseName
6789 + '; IF EXISTS(SELECT * FROM '
6790 + @OutputDatabaseName
6791 + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
6792 + @OutputSchemaName
6793 + ''') AND NOT EXISTS (SELECT * FROM '
6794 + @OutputDatabaseName
6795 + '.INFORMATION_SCHEMA.TABLES WHERE QUOTENAME(TABLE_SCHEMA) = '''
6796 + @OutputSchemaName + ''' AND QUOTENAME(TABLE_NAME) = '''
6797 + @OutputTableName + ''') CREATE TABLE '
6798 + @OutputSchemaName + '.'
6799 + @OutputTableName
6800 + ' (ID INT IDENTITY(1,1) NOT NULL,
6801 ServerName NVARCHAR(128),
6802 CheckDate DATETIME,
6803 AskBrentVersion INT,
6804 CheckID INT NOT NULL,
6805 Priority TINYINT NOT NULL,
6806 FindingsGroup VARCHAR(50) NOT NULL,
6807 Finding VARCHAR(200) NOT NULL,
6808 URL VARCHAR(200) NOT NULL,
6809 Details NVARCHAR(4000) NULL,
6810 HowToStopIt [XML] NULL,
6811 QueryPlan [XML] NULL,
6812 QueryText NVARCHAR(MAX) NULL,
6813 StartTime DATETIME NULL,
6814 LoginName NVARCHAR(128) NULL,
6815 NTUserName NVARCHAR(128) NULL,
6816 OriginalLoginName NVARCHAR(128) NULL,
6817 ProgramName NVARCHAR(128) NULL,
6818 HostName NVARCHAR(128) NULL,
6819 DatabaseID INT NULL,
6820 DatabaseName NVARCHAR(128) NULL,
6821 OpenTransactionCount INT NULL,
6822 CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
6823
6824 EXEC(@StringToExecute);
6825 SET @StringToExecute = N' IF EXISTS(SELECT * FROM '
6826 + @OutputDatabaseName
6827 + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
6828 + @OutputSchemaName + ''') INSERT '
6829 + @OutputDatabaseName + '.'
6830 + @OutputSchemaName + '.'
6831 + @OutputTableName
6832 + ' (ServerName, CheckDate, AskBrentVersion, CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount) SELECT '''
6833 + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
6834 + ''', GETDATE(), ' + CAST(@Version AS NVARCHAR(128))
6835 + ', CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount FROM #AskBrentResults ORDER BY Priority , FindingsGroup , Finding , Details';
6836 EXEC(@StringToExecute);
6837 END
6838 ELSE IF (SUBSTRING(@OutputTableName, 2, 2) = '##')
6839 BEGIN
6840 SET @StringToExecute = N' IF (OBJECT_ID(''tempdb..'
6841 + @OutputTableName
6842 + ''') IS NOT NULL) DROP TABLE ' + @OutputTableName + ';'
6843 + 'CREATE TABLE '
6844 + @OutputTableName
6845 + ' (ID INT IDENTITY(1,1) NOT NULL,
6846 ServerName NVARCHAR(128),
6847 CheckDate DATETIME,
6848 AskBrentVersion INT,
6849 CheckID INT NOT NULL,
6850 Priority TINYINT NOT NULL,
6851 FindingsGroup VARCHAR(50) NOT NULL,
6852 Finding VARCHAR(200) NOT NULL,
6853 URL VARCHAR(200) NOT NULL,
6854 Details NVARCHAR(4000) NULL,
6855 HowToStopIt [XML] NULL,
6856 QueryPlan [XML] NULL,
6857 QueryText NVARCHAR(MAX) NULL,
6858 StartTime DATETIME NULL,
6859 LoginName NVARCHAR(128) NULL,
6860 NTUserName NVARCHAR(128) NULL,
6861 OriginalLoginName NVARCHAR(128) NULL,
6862 ProgramName NVARCHAR(128) NULL,
6863 HostName NVARCHAR(128) NULL,
6864 DatabaseID INT NULL,
6865 DatabaseName NVARCHAR(128) NULL,
6866 OpenTransactionCount INT NULL,
6867 CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
6868 + ' INSERT '
6869 + @OutputTableName
6870 + ' (ServerName, CheckDate, AskBrentVersion, CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, Op) SELECT '''
6871 + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
6872 + ''', GETDATE(), ' + CAST(@Version AS NVARCHAR(128))
6873 + ', CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount FROM #AskBrentResults ORDER BY Priority , FindingsGroup , Finding , Details';
6874 EXEC(@StringToExecute);
6875 END
6876 ELSE IF (SUBSTRING(@OutputTableName, 2, 1) = '#')
6877 BEGIN
6878 RAISERROR('Due to the nature of Dymamic SQL, only global (i.e. double pound (##)) temp tables are supported for @OutputTableName', 16, 0)
6879 END
6880
6881
6882 DECLARE @separator AS VARCHAR(1);
6883 IF @OutputType = 'RSV'
6884 SET @separator = CHAR(31);
6885 ELSE
6886 SET @separator = ',';
6887
6888 IF @OutputType = 'COUNT'
6889 BEGIN
6890 SELECT COUNT(*) AS Warnings
6891 FROM #AskBrentResults
6892 END
6893 ELSE
6894 IF @OutputType = 'Opserver1'
6895 BEGIN
6896
6897 SELECT r.[Priority] ,
6898 r.[FindingsGroup] ,
6899 r.[Finding] ,
6900 r.[URL] ,
6901 r.[Details],
6902 r.[HowToStopIt] ,
6903 r.[CheckID] ,
6904 r.[StartTime],
6905 r.[LoginName],
6906 r.[NTUserName],
6907 r.[OriginalLoginName],
6908 r.[ProgramName],
6909 r.[HostName],
6910 r.[DatabaseID],
6911 r.[DatabaseName],
6912 r.[OpenTransactionCount],
6913 r.[QueryPlan],
6914 r.[QueryText],
6915 qsNow.plan_handle AS PlanHandle,
6916 qsNow.sql_handle AS SqlHandle,
6917 qsNow.statement_start_offset AS StatementStartOffset,
6918 qsNow.statement_end_offset AS StatementEndOffset,
6919 [Executions] = qsNow.execution_count - (COALESCE(qsFirst.execution_count, 0)),
6920 [ExecutionsPercent] = CAST(100.0 * (qsNow.execution_count - (COALESCE(qsFirst.execution_count, 0))) / (qsTotal.execution_count - qsTotalFirst.execution_count) AS DECIMAL(6,2)),
6921 [Duration] = qsNow.total_elapsed_time - (COALESCE(qsFirst.total_elapsed_time, 0)),
6922 [DurationPercent] = CAST(100.0 * (qsNow.total_elapsed_time - (COALESCE(qsFirst.total_elapsed_time, 0))) / (qsTotal.total_elapsed_time - qsTotalFirst.total_elapsed_time) AS DECIMAL(6,2)),
6923 [CPU] = qsNow.total_worker_time - (COALESCE(qsFirst.total_worker_time, 0)),
6924 [CPUPercent] = CAST(100.0 * (qsNow.total_worker_time - (COALESCE(qsFirst.total_worker_time, 0))) / (qsTotal.total_worker_time - qsTotalFirst.total_worker_time) AS DECIMAL(6,2)),
6925 [Reads] = qsNow.total_logical_reads - (COALESCE(qsFirst.total_logical_reads, 0)),
6926 [ReadsPercent] = CAST(100.0 * (qsNow.total_logical_reads - (COALESCE(qsFirst.total_logical_reads, 0))) / (qsTotal.total_logical_reads - qsTotalFirst.total_logical_reads) AS DECIMAL(6,2)),
6927 [PlanCreationTime] = CONVERT(NVARCHAR(100), qsNow.creation_time ,121),
6928 [TotalExecutions] = qsNow.execution_count,
6929 [TotalExecutionsPercent] = CAST(100.0 * qsNow.execution_count / qsTotal.execution_count AS DECIMAL(6,2)),
6930 [TotalDuration] = qsNow.total_elapsed_time,
6931 [TotalDurationPercent] = CAST(100.0 * qsNow.total_elapsed_time / qsTotal.total_elapsed_time AS DECIMAL(6,2)),
6932 [TotalCPU] = qsNow.total_worker_time,
6933 [TotalCPUPercent] = CAST(100.0 * qsNow.total_worker_time / qsTotal.total_worker_time AS DECIMAL(6,2)),
6934 [TotalReads] = qsNow.total_logical_reads,
6935 [TotalReadsPercent] = CAST(100.0 * qsNow.total_logical_reads / qsTotal.total_logical_reads AS DECIMAL(6,2))
6936 FROM #AskBrentResults r
6937 LEFT OUTER JOIN #QueryStats qsTotal ON qsTotal.Pass = 0
6938 LEFT OUTER JOIN #QueryStats qsTotalFirst ON qsTotalFirst.Pass = -1
6939 LEFT OUTER JOIN #QueryStats qsNow ON r.QueryStatsNowID = qsNow.ID
6940 LEFT OUTER JOIN #QueryStats qsFirst ON r.QueryStatsFirstID = qsFirst.ID
6941 ORDER BY r.Priority ,
6942 r.FindingsGroup ,
6943 r.Finding ,
6944 r.ID;
6945 END
6946 ELSE IF @OutputType IN ( 'CSV', 'RSV' )
6947 BEGIN
6948
6949 SELECT Result = CAST([Priority] AS NVARCHAR(100))
6950 + @separator + CAST(CheckID AS NVARCHAR(100))
6951 + @separator + COALESCE([FindingsGroup],
6952 '(N/A)') + @separator
6953 + COALESCE([Finding], '(N/A)') + @separator
6954 + COALESCE(DatabaseName, '(N/A)') + @separator
6955 + COALESCE([URL], '(N/A)') + @separator
6956 + COALESCE([Details], '(N/A)')
6957 FROM #AskBrentResults
6958 ORDER BY Priority ,
6959 FindingsGroup ,
6960 Finding ,
6961 Details;
6962 END
6963 ELSE IF @ExpertMode = 0 AND @OutputXMLasNVARCHAR = 0
6964 BEGIN
6965 SELECT [Priority] ,
6966 [FindingsGroup] ,
6967 [Finding] ,
6968 [URL] ,
6969 CAST(@StockDetailsHeader + [Details] + @StockDetailsFooter AS XML) AS Details,
6970 CAST(@StockWarningHeader + HowToStopIt + @StockWarningFooter AS XML) AS HowToStopId,
6971 [QueryText],
6972 [QueryPlan]
6973 FROM #AskBrentResults
6974 ORDER BY Priority ,
6975 FindingsGroup ,
6976 Finding ,
6977 ID;
6978 END
6979 ELSE IF @ExpertMode = 0 AND @OutputXMLasNVARCHAR = 1
6980 BEGIN
6981 SELECT [Priority] ,
6982 [FindingsGroup] ,
6983 [Finding] ,
6984 [URL] ,
6985 CAST(@StockDetailsHeader + [Details] + @StockDetailsFooter AS NVARCHAR(MAX)) AS Details,
6986 CAST([HowToStopIt] AS NVARCHAR(MAX)) AS HowToStopIt,
6987 CAST([QueryText] AS NVARCHAR(MAX)) AS QueryText,
6988 CAST([QueryPlan] AS NVARCHAR(MAX)) AS QueryPlan
6989 FROM #AskBrentResults
6990 ORDER BY Priority ,
6991 FindingsGroup ,
6992 Finding ,
6993 ID;
6994 END
6995 ELSE IF @ExpertMode = 1
6996 BEGIN
6997 SELECT r.[Priority] ,
6998 r.[FindingsGroup] ,
6999 r.[Finding] ,
7000 r.[URL] ,
7001 CAST(@StockDetailsHeader + r.[Details] + @StockDetailsFooter AS XML) AS Details,
7002 CAST(@StockWarningHeader + r.HowToStopIt + @StockWarningFooter AS XML) AS HowToStopIt,
7003 r.[CheckID] ,
7004 r.[StartTime],
7005 r.[LoginName],
7006 r.[NTUserName],
7007 r.[OriginalLoginName],
7008 r.[ProgramName],
7009 r.[HostName],
7010 r.[DatabaseID],
7011 r.[DatabaseName],
7012 r.[OpenTransactionCount],
7013 r.[QueryPlan],
7014 r.[QueryText],
7015 qsNow.plan_handle AS PlanHandle,
7016 qsNow.sql_handle AS SqlHandle,
7017 qsNow.statement_start_offset AS StatementStartOffset,
7018 qsNow.statement_end_offset AS StatementEndOffset,
7019 [Executions] = qsNow.execution_count - (COALESCE(qsFirst.execution_count, 0)),
7020 [ExecutionsPercent] = CAST(100.0 * (qsNow.execution_count - (COALESCE(qsFirst.execution_count, 0))) / (qsTotal.execution_count - qsTotalFirst.execution_count) AS DECIMAL(6,2)),
7021 [Duration] = qsNow.total_elapsed_time - (COALESCE(qsFirst.total_elapsed_time, 0)),
7022 [DurationPercent] = CAST(100.0 * (qsNow.total_elapsed_time - (COALESCE(qsFirst.total_elapsed_time, 0))) / (qsTotal.total_elapsed_time - qsTotalFirst.total_elapsed_time) AS DECIMAL(6,2)),
7023 [CPU] = qsNow.total_worker_time - (COALESCE(qsFirst.total_worker_time, 0)),
7024 [CPUPercent] = CAST(100.0 * (qsNow.total_worker_time - (COALESCE(qsFirst.total_worker_time, 0))) / (qsTotal.total_worker_time - qsTotalFirst.total_worker_time) AS DECIMAL(6,2)),
7025 [Reads] = qsNow.total_logical_reads - (COALESCE(qsFirst.total_logical_reads, 0)),
7026 [ReadsPercent] = CAST(100.0 * (qsNow.total_logical_reads - (COALESCE(qsFirst.total_logical_reads, 0))) / (qsTotal.total_logical_reads - qsTotalFirst.total_logical_reads) AS DECIMAL(6,2)),
7027 [PlanCreationTime] = CONVERT(NVARCHAR(100), qsNow.creation_time ,121),
7028 [TotalExecutions] = qsNow.execution_count,
7029 [TotalExecutionsPercent] = CAST(100.0 * qsNow.execution_count / qsTotal.execution_count AS DECIMAL(6,2)),
7030 [TotalDuration] = qsNow.total_elapsed_time,
7031 [TotalDurationPercent] = CAST(100.0 * qsNow.total_elapsed_time / qsTotal.total_elapsed_time AS DECIMAL(6,2)),
7032 [TotalCPU] = qsNow.total_worker_time,
7033 [TotalCPUPercent] = CAST(100.0 * qsNow.total_worker_time / qsTotal.total_worker_time AS DECIMAL(6,2)),
7034 [TotalReads] = qsNow.total_logical_reads,
7035 [TotalReadsPercent] = CAST(100.0 * qsNow.total_logical_reads / qsTotal.total_logical_reads AS DECIMAL(6,2))
7036 FROM #AskBrentResults r
7037 LEFT OUTER JOIN #QueryStats qsTotal ON qsTotal.Pass = 0
7038 LEFT OUTER JOIN #QueryStats qsTotalFirst ON qsTotalFirst.Pass = -1
7039 LEFT OUTER JOIN #QueryStats qsNow ON r.QueryStatsNowID = qsNow.ID
7040 LEFT OUTER JOIN #QueryStats qsFirst ON r.QueryStatsFirstID = qsFirst.ID
7041 ORDER BY r.Priority ,
7042 r.FindingsGroup ,
7043 r.Finding ,
7044 r.ID;
7045
7046 -------------------------
7047 --What happened: #WaitStats
7048 -------------------------
7049 ;with max_batch as (
7050 select max(SampleTime) as SampleTime
7051 from #WaitStats
7052 )
7053 SELECT
7054 'WAIT STATS' as Pattern,
7055 b.SampleTime as [Sample Ended],
7056 datediff(ss,wd1.SampleTime, wd2.SampleTime) as [Seconds Sample],
7057 wd1.wait_type,
7058 c.[Wait Time (Seconds)],
7059 c.[Signal Wait Time (Seconds)],
7060 CASE WHEN c.[Wait Time (Seconds)] > 0
7061 THEN CAST(100.*(c.[Signal Wait Time (Seconds)]/c.[Wait Time (Seconds)]) as NUMERIC(4,1))
7062 ELSE 0 END AS [Percent Signal Waits],
7063 (wd2.waiting_tasks_count - wd1.waiting_tasks_count) AS [Number of Waits],
7064 CASE WHEN (wd2.waiting_tasks_count - wd1.waiting_tasks_count) > 0
7065 THEN
7066 cast((wd2.wait_time_ms-wd1.wait_time_ms)/
7067 (1.0*(wd2.waiting_tasks_count - wd1.waiting_tasks_count)) as numeric(10,1))
7068 ELSE 0 END AS [Avg ms Per Wait]
7069 FROM max_batch b
7070 JOIN #WaitStats wd2 on
7071 wd2.SampleTime =b.SampleTime
7072 JOIN #WaitStats wd1 ON
7073 wd1.wait_type=wd2.wait_type AND
7074 wd2.SampleTime > wd1.SampleTime
7075 CROSS APPLY (SELECT
7076 cast((wd2.wait_time_ms-wd1.wait_time_ms)/1000. as numeric(10,1)) as [Wait Time (Seconds)],
7077 cast((wd2.signal_wait_time_ms - wd1.signal_wait_time_ms)/1000. as numeric(10,1)) as [Signal Wait Time (Seconds)]) AS c
7078 WHERE (wd2.waiting_tasks_count - wd1.waiting_tasks_count) > 0
7079 and wd2.wait_time_ms-wd1.wait_time_ms > 0
7080 ORDER BY [Wait Time (Seconds)] DESC;
7081
7082
7083 -------------------------
7084 --What happened: #FileStats
7085 -------------------------
7086 WITH readstats as (
7087 SELECT 'PHYSICAL READS' as Pattern,
7088 ROW_NUMBER() over (order by wd2.avg_stall_read_ms desc) as StallRank,
7089 wd2.SampleTime as [Sample Time],
7090 datediff(ss,wd1.SampleTime, wd2.SampleTime) as [Sample (seconds)],
7091 wd1.DatabaseName ,
7092 wd1.FileLogicalName AS [File Name],
7093 UPPER(SUBSTRING(wd1.PhysicalName, 1, 2)) AS [Drive] ,
7094 wd1.SizeOnDiskMB ,
7095 ( wd2.num_of_reads - wd1.num_of_reads ) AS [# Reads/Writes],
7096 CASE WHEN wd2.num_of_reads - wd1.num_of_reads > 0
7097 THEN CAST(( wd2.bytes_read - wd1.bytes_read)/1024./1024. AS NUMERIC(21,1))
7098 ELSE 0
7099 END AS [MB Read/Written],
7100 wd2.avg_stall_read_ms AS [Avg Stall (ms)],
7101 wd1.PhysicalName AS [file physical name]
7102 FROM #FileStats wd2
7103 JOIN #FileStats wd1 ON wd2.SampleTime > wd1.SampleTime
7104 AND wd1.DatabaseID = wd2.DatabaseID
7105 AND wd1.FileID = wd2.FileID
7106 ),
7107 writestats as (
7108 SELECT
7109 'PHYSICAL WRITES' as Pattern,
7110 ROW_NUMBER() over (order by wd2.avg_stall_write_ms desc) as StallRank,
7111 wd2.SampleTime as [Sample Time],
7112 datediff(ss,wd1.SampleTime, wd2.SampleTime) as [Sample (seconds)],
7113 wd1.DatabaseName ,
7114 wd1.FileLogicalName AS [File Name],
7115 UPPER(SUBSTRING(wd1.PhysicalName, 1, 2)) AS [Drive] ,
7116 wd1.SizeOnDiskMB ,
7117 ( wd2.num_of_writes - wd1.num_of_writes ) AS [# Reads/Writes],
7118 CASE WHEN wd2.num_of_writes - wd1.num_of_writes > 0
7119 THEN CAST(( wd2.bytes_written - wd1.bytes_written)/1024./1024. AS NUMERIC(21,1))
7120 ELSE 0
7121 END AS [MB Read/Written],
7122 wd2.avg_stall_write_ms AS [Avg Stall (ms)],
7123 wd1.PhysicalName AS [file physical name]
7124 FROM #FileStats wd2
7125 JOIN #FileStats wd1 ON wd2.SampleTime > wd1.SampleTime
7126 AND wd1.DatabaseID = wd2.DatabaseID
7127 AND wd1.FileID = wd2.FileID
7128 )
7129 SELECT
7130 Pattern, [Sample Time], [Sample (seconds)], [File Name], [Drive], [# Reads/Writes],[MB Read/Written],[Avg Stall (ms)], [file physical name]
7131 from readstats
7132 where StallRank <=5 and [MB Read/Written] > 0
7133 union all
7134 SELECT Pattern, [Sample Time], [Sample (seconds)], [File Name], [Drive], [# Reads/Writes],[MB Read/Written],[Avg Stall (ms)], [file physical name]
7135 from writestats
7136 where StallRank <=5 and [MB Read/Written] > 0;
7137
7138
7139 -------------------------
7140 --What happened: #PerfmonStats
7141 -------------------------
7142
7143 SELECT 'PERFMON' AS Pattern, pLast.[object_name], pLast.counter_name, pLast.instance_name,
7144 pFirst.SampleTime AS FirstSampleTime, pFirst.cntr_value AS FirstSampleValue,
7145 pLast.SampleTime AS LastSampleTime, pLast.cntr_value AS LastSampleValue,
7146 pLast.cntr_value - pFirst.cntr_value AS ValueDelta,
7147 ((1.0 * pLast.cntr_value - pFirst.cntr_value) / DATEDIFF(ss, pFirst.SampleTime, pLast.SampleTime)) AS ValuePerSecond
7148 FROM #PerfmonStats pLast
7149 INNER JOIN #PerfmonStats pFirst ON pFirst.[object_name] = pLast.[object_name] AND pFirst.counter_name = pLast.counter_name AND (pFirst.instance_name = pLast.instance_name OR (pFirst.instance_name IS NULL AND pLast.instance_name IS NULL))
7150 AND pLast.ID > pFirst.ID
7151 ORDER BY Pattern, pLast.[object_name], pLast.counter_name, pLast.instance_name
7152
7153
7154 -------------------------
7155 --What happened: #FileStats
7156 -------------------------
7157 SELECT qsNow.*, qsFirst.*
7158 FROM #QueryStats qsNow
7159 INNER JOIN #QueryStats qsFirst ON qsNow.[sql_handle] = qsFirst.[sql_handle] AND qsNow.statement_start_offset = qsFirst.statement_start_offset AND qsNow.statement_end_offset = qsFirst.statement_end_offset AND qsNow.plan_generation_num = qsFirst.plan_generation_num AND qsNow.plan_handle = qsFirst.plan_handle AND qsFirst.Pass = 1
7160 WHERE qsNow.Pass = 2
7161 END
7162
7163 DROP TABLE #AskBrentResults;
7164
7165
7166END /* IF @Question IS NULL */
7167ELSE IF @Question IS NOT NULL
7168
7169/* We're playing Magic SQL 8 Ball, so give them an answer. */
7170BEGIN
7171 IF OBJECT_ID('tempdb..#BrentAnswers') IS NOT NULL
7172 DROP TABLE #BrentAnswers;
7173 CREATE TABLE #BrentAnswers(Answer VARCHAR(200) NOT NULL);
7174 INSERT INTO #BrentAnswers VALUES ('It sounds like a SAN problem.');
7175 INSERT INTO #BrentAnswers VALUES ('You know what you need? Bacon.');
7176 INSERT INTO #BrentAnswers VALUES ('Talk to the developers about that.');
7177 INSERT INTO #BrentAnswers VALUES ('Let''s post that on StackOverflow.com and find out.');
7178 INSERT INTO #BrentAnswers VALUES ('Have you tried adding an index?');
7179 INSERT INTO #BrentAnswers VALUES ('Have you tried dropping an index?');
7180 INSERT INTO #BrentAnswers VALUES ('You can''t prove anything.');
7181 INSERT INTO #BrentAnswers VALUES ('If you watched our Tuesday webcasts, you''d already know the answer to that.');
7182 INSERT INTO #BrentAnswers VALUES ('Please phrase the question in the form of an answer.');
7183 INSERT INTO #BrentAnswers VALUES ('Outlook not so good. Access even worse.');
7184 INSERT INTO #BrentAnswers VALUES ('Did you try asking the rubber duck? http://www.codinghorror.com/blog/2012/03/rubber-duck-problem-solving.html');
7185 INSERT INTO #BrentAnswers VALUES ('Oooo, I read about that once.');
7186 INSERT INTO #BrentAnswers VALUES ('I feel your pain.');
7187 INSERT INTO #BrentAnswers VALUES ('http://LMGTFY.com');
7188 INSERT INTO #BrentAnswers VALUES ('No comprende Ingles, senor.');
7189 INSERT INTO #BrentAnswers VALUES ('I don''t have that problem on my Mac.');
7190 INSERT INTO #BrentAnswers VALUES ('Is Priority Boost on?');
7191 INSERT INTO #BrentAnswers VALUES ('Have you tried rebooting your machine?');
7192 INSERT INTO #BrentAnswers VALUES ('Try defragging your cursors.');
7193 INSERT INTO #BrentAnswers VALUES ('Why are you wearing that? Do you have a job interview later or something?');
7194 INSERT INTO #BrentAnswers VALUES ('I''m ashamed that you don''t know the answer to that question.');
7195 INSERT INTO #BrentAnswers VALUES ('What do I look like, a Microsoft Certified Master? Oh, wait...');
7196 INSERT INTO #BrentAnswers VALUES ('Duh, Debra.');
7197 SELECT TOP 1 Answer FROM #BrentAnswers ORDER BY NEWID();
7198END
7199
7200END /* ELSE IF @OutputType = 'SCHEMA' */
7201
7202SET NOCOUNT OFF;
7203GO
7204
7205
7206/* How to run it:
7207EXEC dbo.sp_AskBrent
7208
7209With extra diagnostic info:
7210EXEC dbo.sp_AskBrent @ExpertMode = 1;
7211
7212In Ask a Question mode:
7213EXEC dbo.sp_AskBrent 'Do I need more memory?'
7214
7215A few sample calling methods:
7216EXEC dbo.sp_AskBrent
7217EXEC dbo.sp_AskBrent @ExpertMode = 1;
7218EXEC dbo.sp_AskBrent 'This is a test question';
7219*/
7220----------------------------------------------------------------------------------------------
7221-- Install SP_Blitz
7222----------------------------------------------------------------------------------------------
7223USE [master];
7224GO
7225
7226IF OBJECT_ID('dbo.sp_Blitz') IS NOT NULL
7227 DROP PROC dbo.sp_Blitz;
7228GO
7229
7230CREATE PROCEDURE [dbo].[sp_Blitz]
7231 @CheckUserDatabaseObjects TINYINT = 1 ,
7232 @CheckProcedureCache TINYINT = 0 ,
7233 @OutputType VARCHAR(20) = 'TABLE' ,
7234 @OutputProcedureCache TINYINT = 0 ,
7235 @CheckProcedureCacheFilter VARCHAR(10) = NULL ,
7236 @CheckServerInfo TINYINT = 0 ,
7237 @SkipChecksServer NVARCHAR(256) = NULL ,
7238 @SkipChecksDatabase NVARCHAR(256) = NULL ,
7239 @SkipChecksSchema NVARCHAR(256) = NULL ,
7240 @SkipChecksTable NVARCHAR(256) = NULL ,
7241 @IgnorePrioritiesBelow INT = NULL ,
7242 @IgnorePrioritiesAbove INT = NULL ,
7243 @OutputDatabaseName NVARCHAR(128) = NULL ,
7244 @OutputSchemaName NVARCHAR(256) = NULL ,
7245 @OutputTableName NVARCHAR(256) = NULL ,
7246 @OutputXMLasNVARCHAR TINYINT = 0 ,
7247 @EmailRecipients VARCHAR(MAX) = NULL ,
7248 @EmailProfile sysname = NULL ,
7249 @SummaryMode TINYINT = 0 ,
7250 @Help TINYINT = 0 ,
7251 @Version INT = NULL OUTPUT,
7252 @VersionDate DATETIME = NULL OUTPUT
7253AS
7254 SET NOCOUNT ON;
7255 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
7256 SELECT @Version = 35, @VersionDate = '20140618'
7257
7258 IF @Help = 1 PRINT '
7259 /*
7260 sp_Blitz (TM) v35 - June 18, 2014
7261
7262 (C) 2014, Brent Ozar Unlimited.
7263 See http://BrentOzar.com/go/eula for the End User Licensing Agreement.
7264
7265 To learn more, visit http://www.BrentOzar.com/blitz where you can download
7266 new versions for free, watch training videos on how it works, get more info on
7267 the findings, and more. To contribute code and see your name in the change
7268 log, email your improvements & checks to Help@BrentOzar.com.
7269
7270 Known limitations of this version:
7271 - No support for SQL Server 2000 or compatibility mode 80.
7272 - If a database name has a question mark in it, some tests will fail. Gotta
7273 love that unsupported sp_MSforeachdb.
7274 - If you have offline databases, sp_Blitz fails the first time you run it,
7275 but does work the second time. (Hoo, boy, this will be fun to debug.)
7276
7277 Unknown limitations of this version:
7278 - None. (If we knew them, they would be known. Duh.)
7279
7280 Changes in v35 - June 17, 2014
7281 - John Hill fixed a bug in check 134 looking for deadlocks.
7282 - Robert Virag improved check 19 looking for replication subscribers.
7283 - Russell Hart improved check 34 to avoid blocking during restores.
7284 - Added check 126 for priority boost enabled. It was always in the non-
7285 default configurations check, but this one is so bad we called it out.
7286 - Added checks 128 and 129 for unsupported builds of SQL Server.
7287 - Added check 127 for unneccessary backups of ReportServerTempDB.
7288 - Changed fill factor threshold to <80% to match sp_BlitzIndex.
7289
7290 Changes in v34 - April 2, 2014
7291 - Jason Pritchard fixed a bug in the plan cache analysis that did not return
7292 results when analyzing for high logical reads.
7293 - Kirby Richter @SqlKirby fixed a bug in check 75 (t-log sizes) that failed
7294 on really big transaction log files. (Not even gonna say how big.)
7295 - Oleg Ivashov improved check 94 (jobs without failure emails) to exclude
7296 SSRS jobs.
7297 - Added @SummaryMode parameter to return only one result set per finding.
7298 - Added check 124 for Performance: Deadlocks Happening Daily. Looks for more
7299 than 10 deadlocks per day.
7300 - Moved check 121 for Performance: Serializable Locking to be lower
7301 priority (down to 100 from 10) and only triggers when more than 10
7302 minutes of the wait have happened since startup.
7303 - Changed checks 107-109 for Poison Waits to have higher thresholds, now
7304 looking at more than 5 seconds per hour of server uptime. Been up for 10
7305 hours, we look for 50 seconds, that kind of thing.
7306
7307 Changes in v33 - January 20, 2014
7308 - Bob Klimes fixed a bug that Russell Hart introduced in v32, hahaha. Check
7309 59 was false-alarming on Agent jobs that actually had notifications.
7310
7311 Changes in v32 - January 19, 2014
7312 - Russell Hart fixed a bug in check 59 (Agent jobs without notifications).
7313 - Added @EmailRecipients and @EmailProfile parameters to send the results via
7314 Database Mail. Assumes that database mail is already configured correctly.
7315 Only sends the main results table, and it will not work well if you also
7316 try to use @CheckProcedureCache. Execution plans will not render in email.
7317 - Fixed a bug in checks 108 and 109 that showed poison waits even if they had
7318 0ms of wait time since restart.
7319 - Removed check 120 which warned about backups not using WITH CHECKSUM. We
7320 fell out of love with WITH CHECKSUM - turns out nobody uses it.
7321 - Added check 121 - Poison Wait Detected: Serializable Locking - looking for
7322 waits with %LCK%R%. Happens when a query uses a combination of lock hints
7323 that make the query serializable.
7324 - Added check 122 - User-Created Statistics In Place. There is nothing wrong
7325 with creating your own statistics, but it can cause an IO explosion when
7326 statistics are updated.
7327 - Added check 123 - Multiple Agent Jobs Starting Simultaneously. Ran into an
7328 issue where dozens of jobs started at the exact same time every hour.
7329
7330 Changes in v31 - December 1, 2013
7331 - Dick Baker, Ambrosetti Ltd (UK):
7332 - Fixed typos in checks 107-109 that looked for the wrong CheckID when
7333 skipping checks, plus improved performance while he was in there.
7334 - Improved check 106 (default trace file) so that it will not error out
7335 if the user does not have permissions on sys.traces.
7336 - Christoph Muller-Spengler @cms4j added check 118 looking at the top queries
7337 in the plan cache for key lookups.
7338 - Philip Dietrich added check 119 for TDE certificates that have not been
7339 backed up recently.
7340 - Ricky Lively added @Help to print inline help. I love his approach to it.
7341 - Added check 120 looking for databases that have not had a full backup using
7342 the WITH CHECKSUM option in the last 30 days.
7343
7344 For prior changes, see http://www.BrentOzar.com/blitz/changelog/
7345
7346
7347 Parameter explanations:
7348
7349 @CheckUserDatabaseObjects 1=review user databases for triggers, heaps, etc. Takes more time for more databases and objects.
7350 @CheckServerInfo 1=show server info like CPUs, memory, virtualization
7351 @CheckProcedureCache 1=top 20-50 resource-intensive cache plans and analyze them for common performance issues.
7352 @OutputProcedureCache 1=output the top 20-50 resource-intensive plans even if they did not trigger an alarm
7353 @CheckProcedureCacheFilter ''CPU'' | ''Reads'' | ''Duration'' | ''ExecCount''
7354 @OutputType ''TABLE''=table | ''COUNT''=row with number found | ''SCHEMA''=version and field list
7355 @IgnorePrioritiesBelow 100=ignore priorities below 100
7356 @IgnorePrioritiesAbove 100=ignore priorities above 100
7357 For the rest of the parameters, see http://www.brentozar.com/blitz/documentation for details.
7358
7359
7360 */'
7361 ELSE IF @OutputType = 'SCHEMA'
7362 BEGIN
7363 SELECT @Version AS Version,
7364 FieldList = '[Priority] TINYINT, [FindingsGroup] VARCHAR(50), [Finding] VARCHAR(200), [DatabaseName] NVARCHAR(128), [URL] VARCHAR(200), [Details] NVARCHAR(4000), [QueryPlan] NVARCHAR(MAX), [QueryPlanFiltered] NVARCHAR(MAX), [CheckID] INT'
7365
7366 END
7367 ELSE /* IF @OutputType = 'SCHEMA' */
7368 BEGIN
7369
7370 /*
7371 We start by creating #BlitzResults. It's a temp table that will store all of
7372 the results from our checks. Throughout the rest of this stored procedure,
7373 we're running a series of checks looking for dangerous things inside the SQL
7374 Server. When we find a problem, we insert rows into #BlitzResults. At the
7375 end, we return these results to the end user.
7376
7377 #BlitzResults has a CheckID field, but there's no Check table. As we do
7378 checks, we insert data into this table, and we manually put in the CheckID.
7379 We (Brent Ozar Unlimited) maintain a list of the checks by ID#. You can
7380 download that from http://www.BrentOzar.com/blitz/documentation/ - you'll
7381 see why it can help shortly.
7382 */
7383 DECLARE @StringToExecute NVARCHAR(4000)
7384 ,@curr_tracefilename NVARCHAR(500)
7385 ,@base_tracefilename NVARCHAR(500)
7386 ,@indx int
7387 ,@query_result_separator CHAR(1)
7388 ,@EmailSubject NVARCHAR(255)
7389 ,@EmailBody NVARCHAR(MAX)
7390 ,@EmailAttachmentFilename NVARCHAR(255)
7391 ,@ProductVersion NVARCHAR(128)
7392 ,@ProductVersionMajor DECIMAL(10,2)
7393 ,@ProductVersionMinor DECIMAL(10,2);
7394
7395 IF OBJECT_ID('tempdb..#BlitzResults') IS NOT NULL
7396 DROP TABLE #BlitzResults;
7397 CREATE TABLE #BlitzResults
7398 (
7399 ID INT IDENTITY(1, 1) ,
7400 CheckID INT ,
7401 DatabaseName NVARCHAR(128) ,
7402 Priority TINYINT ,
7403 FindingsGroup VARCHAR(50) ,
7404 Finding VARCHAR(200) ,
7405 URL VARCHAR(200) ,
7406 Details NVARCHAR(4000) ,
7407 QueryPlan [XML] NULL ,
7408 QueryPlanFiltered [NVARCHAR](MAX) NULL
7409 );
7410
7411 /*
7412 You can build your own table with a list of checks to skip. For example, you
7413 might have some databases that you don't care about, or some checks you don't
7414 want to run. Then, when you run sp_Blitz, you can specify these parameters:
7415 @SkipChecksDatabase = 'DBAtools',
7416 @SkipChecksSchema = 'dbo',
7417 @SkipChecksTable = 'BlitzChecksToSkip'
7418 Pass in the database, schema, and table that contains the list of checks you
7419 want to skip. This part of the code checks those parameters, gets the list,
7420 and then saves those in a temp table. As we run each check, we'll see if we
7421 need to skip it.
7422
7423 Really anal-retentive users will note that the @SkipChecksServer parameter is
7424 not used. YET. We added that parameter in so that we could avoid changing the
7425 stored proc's surface area (interface) later.
7426 */
7427 IF OBJECT_ID('tempdb..#SkipChecks') IS NOT NULL
7428 DROP TABLE #SkipChecks;
7429 CREATE TABLE #SkipChecks
7430 (
7431 DatabaseName NVARCHAR(128) ,
7432 CheckID INT ,
7433 ServerName NVARCHAR(128)
7434 );
7435 CREATE CLUSTERED INDEX IX_CheckID_DatabaseName ON #SkipChecks(CheckID, DatabaseName);
7436
7437 IF @SkipChecksTable IS NOT NULL
7438 AND @SkipChecksSchema IS NOT NULL
7439 AND @SkipChecksDatabase IS NOT NULL
7440 BEGIN
7441 SET @StringToExecute = 'INSERT INTO #SkipChecks(DatabaseName, CheckID, ServerName )
7442 SELECT DISTINCT DatabaseName, CheckID, ServerName
7443 FROM ' + QUOTENAME(@SkipChecksDatabase) + '.' + QUOTENAME(@SkipChecksSchema) + '.' + QUOTENAME(@SkipChecksTable)
7444 + ' WHERE ServerName IS NULL OR ServerName = SERVERPROPERTY(''ServerName'');'
7445 EXEC(@StringToExecute)
7446 END
7447
7448 IF NOT EXISTS ( SELECT 1
7449 FROM #SkipChecks
7450 WHERE DatabaseName IS NULL AND CheckID = 106 )
7451 AND (select convert(int,value_in_use) from sys.configurations where name = 'default trace enabled' ) = 1
7452 BEGIN
7453 select @curr_tracefilename = [path] from sys.traces where is_default = 1 ;
7454 set @curr_tracefilename = reverse(@curr_tracefilename);
7455 select @indx = patindex('%\%', @curr_tracefilename) ;
7456 set @curr_tracefilename = reverse(@curr_tracefilename) ;
7457 set @base_tracefilename = left( @curr_tracefilename,len(@curr_tracefilename) - @indx) + '\log.trc' ;
7458 END
7459
7460
7461 /*
7462 That's the end of the SkipChecks stuff.
7463 The next several tables are used by various checks later.
7464 */
7465 IF OBJECT_ID('tempdb..#ConfigurationDefaults') IS NOT NULL
7466 DROP TABLE #ConfigurationDefaults;
7467 CREATE TABLE #ConfigurationDefaults
7468 (
7469 name NVARCHAR(128) ,
7470 DefaultValue BIGINT,
7471 CheckID INT
7472 );
7473
7474 IF OBJECT_ID('tempdb..#DBCCs') IS NOT NULL
7475 DROP TABLE #DBCCs;
7476 CREATE TABLE #DBCCs
7477 (
7478 ID INT IDENTITY(1, 1)
7479 PRIMARY KEY ,
7480 ParentObject VARCHAR(255) ,
7481 Object VARCHAR(255) ,
7482 Field VARCHAR(255) ,
7483 Value VARCHAR(255) ,
7484 DbName NVARCHAR(128) NULL
7485 )
7486
7487
7488 IF OBJECT_ID('tempdb..#LogInfo2012') IS NOT NULL
7489 DROP TABLE #LogInfo2012;
7490 CREATE TABLE #LogInfo2012
7491 (
7492 recoveryunitid INT ,
7493 FileID SMALLINT ,
7494 FileSize BIGINT ,
7495 StartOffset BIGINT ,
7496 FSeqNo BIGINT ,
7497 [Status] TINYINT ,
7498 Parity TINYINT ,
7499 CreateLSN NUMERIC(38)
7500 );
7501
7502 IF OBJECT_ID('tempdb..#LogInfo') IS NOT NULL
7503 DROP TABLE #LogInfo;
7504 CREATE TABLE #LogInfo
7505 (
7506 FileID SMALLINT ,
7507 FileSize BIGINT ,
7508 StartOffset BIGINT ,
7509 FSeqNo BIGINT ,
7510 [Status] TINYINT ,
7511 Parity TINYINT ,
7512 CreateLSN NUMERIC(38)
7513 );
7514
7515 IF OBJECT_ID('tempdb..#partdb') IS NOT NULL
7516 DROP TABLE #partdb;
7517 CREATE TABLE #partdb
7518 (
7519 dbname NVARCHAR(128) ,
7520 objectname NVARCHAR(200) ,
7521 type_desc NVARCHAR(128)
7522 )
7523
7524 IF OBJECT_ID('tempdb..#TraceStatus') IS NOT NULL
7525 DROP TABLE #TraceStatus;
7526 CREATE TABLE #TraceStatus
7527 (
7528 TraceFlag VARCHAR(10) ,
7529 status BIT ,
7530 Global BIT ,
7531 Session BIT
7532 );
7533
7534 IF OBJECT_ID('tempdb..#driveInfo') IS NOT NULL
7535 DROP TABLE #driveInfo;
7536 CREATE TABLE #driveInfo
7537 (
7538 drive NVARCHAR ,
7539 SIZE DECIMAL(18, 2)
7540 )
7541
7542
7543 IF OBJECT_ID('tempdb..#dm_exec_query_stats') IS NOT NULL
7544 DROP TABLE #dm_exec_query_stats;
7545 CREATE TABLE #dm_exec_query_stats
7546 (
7547 [id] [int] NOT NULL
7548 IDENTITY(1, 1) ,
7549 [sql_handle] [varbinary](64) NOT NULL ,
7550 [statement_start_offset] [int] NOT NULL ,
7551 [statement_end_offset] [int] NOT NULL ,
7552 [plan_generation_num] [bigint] NOT NULL ,
7553 [plan_handle] [varbinary](64) NOT NULL ,
7554 [creation_time] [datetime] NOT NULL ,
7555 [last_execution_time] [datetime] NOT NULL ,
7556 [execution_count] [bigint] NOT NULL ,
7557 [total_worker_time] [bigint] NOT NULL ,
7558 [last_worker_time] [bigint] NOT NULL ,
7559 [min_worker_time] [bigint] NOT NULL ,
7560 [max_worker_time] [bigint] NOT NULL ,
7561 [total_physical_reads] [bigint] NOT NULL ,
7562 [last_physical_reads] [bigint] NOT NULL ,
7563 [min_physical_reads] [bigint] NOT NULL ,
7564 [max_physical_reads] [bigint] NOT NULL ,
7565 [total_logical_writes] [bigint] NOT NULL ,
7566 [last_logical_writes] [bigint] NOT NULL ,
7567 [min_logical_writes] [bigint] NOT NULL ,
7568 [max_logical_writes] [bigint] NOT NULL ,
7569 [total_logical_reads] [bigint] NOT NULL ,
7570 [last_logical_reads] [bigint] NOT NULL ,
7571 [min_logical_reads] [bigint] NOT NULL ,
7572 [max_logical_reads] [bigint] NOT NULL ,
7573 [total_clr_time] [bigint] NOT NULL ,
7574 [last_clr_time] [bigint] NOT NULL ,
7575 [min_clr_time] [bigint] NOT NULL ,
7576 [max_clr_time] [bigint] NOT NULL ,
7577 [total_elapsed_time] [bigint] NOT NULL ,
7578 [last_elapsed_time] [bigint] NOT NULL ,
7579 [min_elapsed_time] [bigint] NOT NULL ,
7580 [max_elapsed_time] [bigint] NOT NULL ,
7581 [query_hash] [binary](8) NULL ,
7582 [query_plan_hash] [binary](8) NULL ,
7583 [query_plan] [xml] NULL ,
7584 [query_plan_filtered] [nvarchar](MAX) NULL ,
7585 [text] [nvarchar](MAX) COLLATE SQL_Latin1_General_CP1_CI_AS
7586 NULL ,
7587 [text_filtered] [nvarchar](MAX) COLLATE SQL_Latin1_General_CP1_CI_AS
7588 NULL
7589 )
7590
7591
7592 /* If we're outputting CSV, don't bother checking the plan cache because we cannot export plans. */
7593 IF @OutputType = 'CSV'
7594 SET @CheckProcedureCache = 0;
7595
7596 /* Sanitize our inputs */
7597 SELECT
7598 @OutputDatabaseName = QUOTENAME(@OutputDatabaseName),
7599 @OutputSchemaName = QUOTENAME(@OutputSchemaName),
7600 @OutputTableName = QUOTENAME(@OutputTableName)
7601
7602 /* Get the major and minor build numbers */
7603 SET @ProductVersion = CAST(SERVERPROPERTY('ProductVersion') AS NVARCHAR(128));
7604 SELECT @ProductVersionMajor = SUBSTRING(@ProductVersion, 1,CHARINDEX('.', @ProductVersion) + 1 ),
7605 @ProductVersionMinor = PARSENAME(CONVERT(varchar(32), @ProductVersion), 2)
7606
7607
7608 /*
7609 Whew! we're finally done with the setup, and we can start doing checks.
7610 First, let's make sure we're actually supposed to do checks on this server.
7611 The user could have passed in a SkipChecks table that specified to skip ALL
7612 checks on this server, so let's check for that:
7613 */
7614 IF ( ( SERVERPROPERTY('ServerName') NOT IN ( SELECT ServerName
7615 FROM #SkipChecks
7616 WHERE DatabaseName IS NULL
7617 AND CheckID IS NULL ) )
7618 OR ( @SkipChecksTable IS NULL )
7619 )
7620 BEGIN
7621
7622 /*
7623 Our very first check! We'll put more comments in this one just to
7624 explain exactly how it works. First, we check to see if we're
7625 supposed to skip CheckID 1 (that's the check we're working on.)
7626 */
7627 IF NOT EXISTS ( SELECT 1
7628 FROM #SkipChecks
7629 WHERE DatabaseName IS NULL AND CheckID = 1 )
7630 BEGIN
7631
7632 /*
7633 Below, we check master.sys.databases looking for databases
7634 that haven't had a backup in the last week. If we find any,
7635 we insert them into #BlitzResults, the temp table that
7636 tracks our server's problems. Note that if the check does
7637 NOT find any problems, we don't save that. We're only
7638 saving the problems, not the successful checks.
7639 */
7640 INSERT INTO #BlitzResults
7641 ( CheckID ,
7642 DatabaseName ,
7643 Priority ,
7644 FindingsGroup ,
7645 Finding ,
7646 URL ,
7647 Details
7648 )
7649 SELECT 1 AS CheckID ,
7650 d.[name] AS DatabaseName ,
7651 1 AS Priority ,
7652 'Backup' AS FindingsGroup ,
7653 'Backups Not Performed Recently' AS Finding ,
7654 'http://BrentOzar.com/go/nobak' AS URL ,
7655 'Database ' + d.Name + ' last backed up: '
7656 + CAST(COALESCE(MAX(b.backup_finish_date),
7657 ' never ') AS VARCHAR(200)) AS Details
7658 FROM master.sys.databases d
7659 LEFT OUTER JOIN msdb.dbo.backupset b ON d.name COLLATE SQL_Latin1_General_CP1_CI_AS = b.database_name COLLATE SQL_Latin1_General_CP1_CI_AS
7660 AND b.type = 'D'
7661 AND b.server_name = SERVERPROPERTY('ServerName') /*Backupset ran on current server */
7662 WHERE d.database_id <> 2 /* Bonus points if you know what that means */
7663 AND d.state <> 1 /* Not currently restoring, like log shipping databases */
7664 AND d.is_in_standby = 0 /* Not a log shipping target database */
7665 AND d.source_database_id IS NULL /* Excludes database snapshots */
7666 AND d.name NOT IN ( SELECT DISTINCT
7667 DatabaseName
7668 FROM #SkipChecks
7669 WHERE CheckID IS NULL )
7670 /*
7671 The above NOT IN filters out the databases we're not supposed to check.
7672 */
7673 GROUP BY d.name
7674 HAVING MAX(b.backup_finish_date) <= DATEADD(dd,
7675 -7, GETDATE());
7676 /*
7677 And there you have it. The rest of this stored procedure works the same
7678 way: it asks:
7679 - Should I skip this check?
7680 - If not, do I find problems?
7681 - Insert the results into #BlitzResults
7682 This particular check is just a little bit fancy - it also has a second
7683 query below that checks for databases that have NEVER been backed up.
7684 We use CheckID #1 for both of these just because they represent the same
7685 problem - a database that needs a backup.
7686 */
7687
7688 INSERT INTO #BlitzResults
7689 ( CheckID ,
7690 DatabaseName ,
7691 Priority ,
7692 FindingsGroup ,
7693 Finding ,
7694 URL ,
7695 Details
7696 )
7697 SELECT 1 AS CheckID ,
7698 d.name AS DatabaseName ,
7699 1 AS Priority ,
7700 'Backup' AS FindingsGroup ,
7701 'Backups Not Performed Recently' AS Finding ,
7702 'http://BrentOzar.com/go/nobak' AS URL ,
7703 ( 'Database ' + d.Name
7704 + ' never backed up.' ) AS Details
7705 FROM master.sys.databases d
7706 WHERE d.database_id <> 2 /* Bonus points if you know what that means */
7707 AND d.state <> 1 /* Not currently restoring, like log shipping databases */
7708 AND d.is_in_standby = 0 /* Not a log shipping target database */
7709 AND d.source_database_id IS NULL /* Excludes database snapshots */
7710 AND d.name NOT IN ( SELECT DISTINCT
7711 DatabaseName
7712 FROM #SkipChecks
7713 WHERE CheckID IS NULL )
7714 AND NOT EXISTS ( SELECT *
7715 FROM msdb.dbo.backupset b
7716 WHERE d.name COLLATE SQL_Latin1_General_CP1_CI_AS = b.database_name COLLATE SQL_Latin1_General_CP1_CI_AS
7717 AND b.type = 'D'
7718 AND b.server_name = SERVERPROPERTY('ServerName') /*Backupset ran on current server */)
7719
7720 END
7721
7722 /*
7723 And that's the end of CheckID #1.
7724
7725 CheckID #2 is a little simpler because it only involves one query, and it's
7726 more typical for queries that people contribute. But keep reading, because
7727 the next check gets more complex again.
7728 */
7729
7730 IF NOT EXISTS ( SELECT 1
7731 FROM #SkipChecks
7732 WHERE DatabaseName IS NULL AND CheckID = 2 )
7733 BEGIN
7734 INSERT INTO #BlitzResults
7735 ( CheckID ,
7736 DatabaseName ,
7737 Priority ,
7738 FindingsGroup ,
7739 Finding ,
7740 URL ,
7741 Details
7742 )
7743 SELECT DISTINCT
7744 2 AS CheckID ,
7745 d.name AS DatabaseName ,
7746 1 AS Priority ,
7747 'Backup' AS FindingsGroup ,
7748 'Full Recovery Mode w/o Log Backups' AS Finding ,
7749 'http://BrentOzar.com/go/biglogs' AS URL ,
7750 ( 'Database ' + ( d.Name COLLATE database_default )
7751 + ' is in ' + d.recovery_model_desc
7752 + ' recovery mode but has not had a log backup in the last week.' ) AS Details
7753 FROM master.sys.databases d
7754 WHERE d.recovery_model IN ( 1, 2 )
7755 AND d.database_id NOT IN ( 2, 3 )
7756 AND d.source_database_id IS NULL
7757 AND d.state <> 1 /* Not currently restoring, like log shipping databases */
7758 AND d.is_in_standby = 0 /* Not a log shipping target database */
7759 AND d.source_database_id IS NULL /* Excludes database snapshots */
7760 AND d.name NOT IN ( SELECT DISTINCT
7761 DatabaseName
7762 FROM #SkipChecks
7763 WHERE CheckID IS NULL )
7764 AND NOT EXISTS ( SELECT *
7765 FROM msdb.dbo.backupset b
7766 WHERE d.name COLLATE SQL_Latin1_General_CP1_CI_AS = b.database_name COLLATE SQL_Latin1_General_CP1_CI_AS
7767 AND b.type = 'L'
7768 AND b.backup_finish_date >= DATEADD(dd,
7769 -7, GETDATE()) );
7770 END
7771
7772
7773 /*
7774 Next up, we've got CheckID 8. (These don't have to go in order.) This one
7775 won't work on SQL Server 2005 because it relies on a new DMV that didn't
7776 exist prior to SQL Server 2008. This means we have to check the SQL Server
7777 version first, then build a dynamic string with the query we want to run:
7778 */
7779
7780 IF NOT EXISTS ( SELECT 1
7781 FROM #SkipChecks
7782 WHERE DatabaseName IS NULL AND CheckID = 8 )
7783 BEGIN
7784 IF @@VERSION NOT LIKE '%Microsoft SQL Server 2000%'
7785 AND @@VERSION NOT LIKE '%Microsoft SQL Server 2005%'
7786 BEGIN
7787 SET @StringToExecute = 'INSERT INTO #BlitzResults
7788 (CheckID, Priority,
7789 FindingsGroup,
7790 Finding, URL,
7791 Details)
7792 SELECT 8 AS CheckID,
7793 150 AS Priority,
7794 ''Security'' AS FindingsGroup,
7795 ''Server Audits Running'' AS Finding,
7796 ''http://BrentOzar.com/go/audits'' AS URL,
7797 (''SQL Server built-in audit functionality is being used by server audit: '' + [name]) AS Details FROM sys.dm_server_audit_status'
7798 EXECUTE(@StringToExecute)
7799 END;
7800 END
7801
7802 /*
7803 But what if you need to run a query in every individual database?
7804 Check out CheckID 99 below. Yes, it uses sp_MSforeachdb, and no,
7805 we're not happy about that. sp_MSforeachdb is known to have a lot
7806 of issues, like skipping databases sometimes. However, this is the
7807 only built-in option that we have. If you're writing your own code
7808 for database maintenance, consider Aaron Bertrand's alternative:
7809 http://www.mssqltips.com/sqlservertip/2201/making-a-more-reliable-and-flexible-spmsforeachdb/
7810 We don't include that as part of sp_Blitz, of course, because
7811 copying and distributing copyrighted code from others without their
7812 written permission isn't a good idea.
7813 */
7814 IF NOT EXISTS ( SELECT 1
7815 FROM #SkipChecks
7816 WHERE DatabaseName IS NULL AND CheckID = 99 )
7817 BEGIN
7818 EXEC dbo.sp_MSforeachdb 'USE [?]; IF EXISTS (SELECT * FROM sys.tables WITH (NOLOCK) WHERE name = ''sysmergepublications'' ) IF EXISTS ( SELECT * FROM sysmergepublications WITH (NOLOCK) WHERE retention = 0) INSERT INTO #BlitzResults (CheckID, DatabaseName, Priority, FindingsGroup, Finding, URL, Details) SELECT DISTINCT 99, DB_NAME(), 110, ''Performance'', ''Infinite merge replication metadata retention period'', ''http://BrentOzar.com/go/merge'', (''The ['' + DB_NAME() + ''] database has merge replication metadata retention period set to infinite - this can be the case of significant performance issues.'')';
7819 END
7820 /*
7821 Note that by using sp_MSforeachdb, we're running the query in all
7822 databases. We're not checking #SkipChecks here for each database to
7823 see if we should run the check in this database. That means we may
7824 still run a skipped check if it involves sp_MSforeachdb. We just
7825 don't output those results in the last step.
7826
7827 And that's the basic idea! You can read through the rest of the
7828 checks if you like - some more exciting stuff happens closer to the
7829 end of the stored proc, where we start doing things like checking
7830 the plan cache, but those aren't as cleanly commented.
7831
7832 If you'd like to contribute your own check, use one of the check
7833 formats shown above and email it to Help@BrentOzar.com. You don't
7834 have to pick a CheckID or a link - we'll take care of that when we
7835 test and publish the code. Thanks!
7836 */
7837
7838
7839 IF NOT EXISTS ( SELECT 1
7840 FROM #SkipChecks
7841 WHERE DatabaseName IS NULL AND CheckID = 93 )
7842 BEGIN
7843 INSERT INTO #BlitzResults
7844 ( CheckID ,
7845 Priority ,
7846 FindingsGroup ,
7847 Finding ,
7848 URL ,
7849 Details
7850 )
7851 SELECT DISTINCT
7852 93 AS CheckID ,
7853 1 AS Priority ,
7854 'Backup' AS FindingsGroup ,
7855 'Backing Up to Same Drive Where Databases Reside' AS Finding ,
7856 'http://BrentOzar.com/go/backup' AS URL ,
7857 'Drive '
7858 + UPPER(LEFT(bmf.physical_device_name, 3))
7859 + ' houses both database files AND backups taken in the last two weeks. This represents a serious risk if that array fails.' Details
7860 FROM msdb.dbo.backupmediafamily AS bmf
7861 INNER JOIN msdb.dbo.backupset AS bs ON bmf.media_set_id = bs.media_set_id
7862 AND bs.backup_start_date >= ( DATEADD(dd,
7863 -14, GETDATE()) )
7864 WHERE UPPER(LEFT(bmf.physical_device_name COLLATE SQL_Latin1_General_CP1_CI_AS, 3)) IN (
7865 SELECT DISTINCT
7866 UPPER(LEFT(mf.physical_name COLLATE SQL_Latin1_General_CP1_CI_AS, 3))
7867 FROM sys.master_files AS mf )
7868 END
7869
7870
7871 IF NOT EXISTS ( SELECT 1
7872 FROM #SkipChecks
7873 WHERE DatabaseName IS NULL AND CheckID = 119 )
7874 AND EXISTS ( SELECT *
7875 FROM sys.all_objects o
7876 WHERE o.name = 'dm_database_encryption_keys' )
7877 BEGIN
7878 SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, DatabaseName, URL, Details)
7879 SELECT 119 AS CheckID,
7880 1 AS Priority,
7881 ''Backup'' AS FindingsGroup,
7882 ''TDE Certificate Not Backed Up Recently'' AS Finding,
7883 db_name(dek.database_id) AS DatabaseName,
7884 ''http://BrentOzar.com/go/tde'' AS URL,
7885 ''The certificate '' + c.name + '' is used to encrypt database '' + db_name(dek.database_id) + ''. Last backup date: '' + COALESCE(CAST(c.pvt_key_last_backup_date AS VARCHAR(100)), ''Never'') AS Details
7886 FROM sys.certificates c INNER JOIN sys.dm_database_encryption_keys dek ON c.thumbprint = dek.encryptor_thumbprint
7887 WHERE pvt_key_last_backup_date IS NULL OR pvt_key_last_backup_date <= DATEADD(dd, -30, GETDATE())';
7888 EXECUTE(@StringToExecute);
7889 END
7890
7891
7892 IF NOT EXISTS ( SELECT 1
7893 FROM #SkipChecks
7894 WHERE DatabaseName IS NULL AND CheckID = 3 )
7895 BEGIN
7896 INSERT INTO #BlitzResults
7897 ( CheckID ,
7898 DatabaseName ,
7899 Priority ,
7900 FindingsGroup ,
7901 Finding ,
7902 URL ,
7903 Details
7904 )
7905 SELECT TOP 1
7906 3 AS CheckID ,
7907 'msdb' ,
7908 200 AS Priority ,
7909 'Backup' AS FindingsGroup ,
7910 'MSDB Backup History Not Purged' AS Finding ,
7911 'http://BrentOzar.com/go/history' AS URL ,
7912 ( 'Database backup history retained back to '
7913 + CAST(bs.backup_start_date AS VARCHAR(20)) ) AS Details
7914 FROM msdb.dbo.backupset bs
7915 WHERE bs.backup_start_date <= DATEADD(dd, -60,
7916 GETDATE())
7917 ORDER BY backup_set_id ASC;
7918 END
7919
7920 IF NOT EXISTS ( SELECT 1
7921 FROM #SkipChecks
7922 WHERE DatabaseName IS NULL AND CheckID = 4 )
7923 BEGIN
7924 INSERT INTO #BlitzResults
7925 ( CheckID ,
7926 Priority ,
7927 FindingsGroup ,
7928 Finding ,
7929 URL ,
7930 Details
7931 )
7932 SELECT 4 AS CheckID ,
7933 10 AS Priority ,
7934 'Security' AS FindingsGroup ,
7935 'Sysadmins' AS Finding ,
7936 'http://BrentOzar.com/go/sa' AS URL ,
7937 ( 'Login [' + l.name
7938 + '] is a sysadmin - meaning they can do absolutely anything in SQL Server, including dropping databases or hiding their tracks.' ) AS Details
7939 FROM master.sys.syslogins l
7940 WHERE l.sysadmin = 1
7941 AND l.name <> SUSER_SNAME(0x01)
7942 AND l.denylogin = 0;
7943 END
7944
7945
7946 IF NOT EXISTS ( SELECT 1
7947 FROM #SkipChecks
7948 WHERE DatabaseName IS NULL AND CheckID = 5 )
7949 BEGIN
7950 INSERT INTO #BlitzResults
7951 ( CheckID ,
7952 Priority ,
7953 FindingsGroup ,
7954 Finding ,
7955 URL ,
7956 Details
7957 )
7958 SELECT 5 AS CheckID ,
7959 10 AS Priority ,
7960 'Security' AS FindingsGroup ,
7961 'Security Admins' AS Finding ,
7962 'http://BrentOzar.com/go/sa' AS URL ,
7963 ( 'Login [' + l.name
7964 + '] is a security admin - meaning they can give themselves permission to do absolutely anything in SQL Server, including dropping databases or hiding their tracks.' ) AS Details
7965 FROM master.sys.syslogins l
7966 WHERE l.securityadmin = 1
7967 AND l.name <> SUSER_SNAME(0x01)
7968 AND l.denylogin = 0;
7969 END
7970
7971 IF NOT EXISTS ( SELECT 1
7972 FROM #SkipChecks
7973 WHERE DatabaseName IS NULL AND CheckID = 104 )
7974 BEGIN
7975 INSERT INTO #BlitzResults
7976 ( [CheckID] ,
7977 [Priority] ,
7978 [FindingsGroup] ,
7979 [Finding] ,
7980 [URL] ,
7981 [Details]
7982 )
7983 SELECT 104 AS [CheckID] ,
7984 10 AS [Priority] ,
7985 'Security' AS [FindingsGroup] ,
7986 'Login Can Control Server' AS [Finding] ,
7987 'http://BrentOzar.com/go/sa' AS [URL] ,
7988 'Login [' + pri.[name]
7989 + '] has the CONTROL SERVER permission - meaning they can do absolutely anything in SQL Server, including dropping databases or hiding their tracks.' AS [Details]
7990 FROM sys.server_principals AS pri
7991 WHERE pri.[principal_id] IN (
7992 SELECT p.[grantee_principal_id]
7993 FROM sys.server_permissions AS p
7994 WHERE p.[state] IN ( 'G', 'W' )
7995 AND p.[class] = 100
7996 AND p.[type] = 'CL' )
7997 AND pri.[name] NOT LIKE '##%##'
7998 END
7999
8000 IF NOT EXISTS ( SELECT 1
8001 FROM #SkipChecks
8002 WHERE DatabaseName IS NULL AND CheckID = 6 )
8003 BEGIN
8004 INSERT INTO #BlitzResults
8005 ( CheckID ,
8006 Priority ,
8007 FindingsGroup ,
8008 Finding ,
8009 URL ,
8010 Details
8011 )
8012 SELECT 6 AS CheckID ,
8013 200 AS Priority ,
8014 'Security' AS FindingsGroup ,
8015 'Jobs Owned By Users' AS Finding ,
8016 'http://BrentOzar.com/go/owners' AS URL ,
8017 ( 'Job [' + j.name + '] is owned by ['
8018 + SUSER_SNAME(j.owner_sid)
8019 + '] - meaning if their login is disabled or not available due to Active Directory problems, the job will stop working.' ) AS Details
8020 FROM msdb.dbo.sysjobs j
8021 WHERE j.enabled = 1
8022 AND SUSER_SNAME(j.owner_sid) <> SUSER_SNAME(0x01);
8023 END
8024
8025
8026 IF NOT EXISTS ( SELECT 1
8027 FROM #SkipChecks
8028 WHERE DatabaseName IS NULL AND CheckID = 7 )
8029 BEGIN
8030 INSERT INTO #BlitzResults
8031 ( CheckID ,
8032 Priority ,
8033 FindingsGroup ,
8034 Finding ,
8035 URL ,
8036 Details
8037 )
8038 SELECT 7 AS CheckID ,
8039 10 AS Priority ,
8040 'Security' AS FindingsGroup ,
8041 'Stored Procedure Runs at Startup' AS Finding ,
8042 'http://BrentOzar.com/go/startup' AS URL ,
8043 ( 'Stored procedure [master].['
8044 + r.SPECIFIC_SCHEMA + '].['
8045 + r.SPECIFIC_NAME
8046 + '] runs automatically when SQL Server starts up. Make sure you know exactly what this stored procedure is doing, because it could pose a security risk.' ) AS Details
8047 FROM master.INFORMATION_SCHEMA.ROUTINES r
8048 WHERE OBJECTPROPERTY(OBJECT_ID(ROUTINE_NAME),
8049 'ExecIsStartup') = 1;
8050 END
8051
8052
8053 IF NOT EXISTS ( SELECT 1
8054 FROM #SkipChecks
8055 WHERE DatabaseName IS NULL AND CheckID = 9 )
8056 BEGIN
8057 IF @@VERSION NOT LIKE '%Microsoft SQL Server 2000%'
8058 BEGIN
8059 SET @StringToExecute = 'INSERT INTO #BlitzResults
8060 (CheckID,
8061 Priority,
8062 FindingsGroup,
8063 Finding,
8064 URL,
8065 Details)
8066 SELECT 9 AS CheckID,
8067 200 AS Priority,
8068 ''Surface Area'' AS FindingsGroup,
8069 ''Endpoints Configured'' AS Finding,
8070 ''http://BrentOzar.com/go/endpoints/'' AS URL,
8071 (''SQL Server endpoints are configured. These can be used for database mirroring or Service Broker, but if you do not need them, avoid leaving them enabled. Endpoint name: '' + [name]) AS Details FROM sys.endpoints WHERE type <> 2'
8072 EXECUTE(@StringToExecute)
8073 END;
8074 END
8075
8076
8077 IF NOT EXISTS ( SELECT 1
8078 FROM #SkipChecks
8079 WHERE DatabaseName IS NULL AND CheckID = 10 )
8080 BEGIN
8081 IF @@VERSION NOT LIKE '%Microsoft SQL Server 2000%'
8082 AND @@VERSION NOT LIKE '%Microsoft SQL Server 2005%'
8083 BEGIN
8084 SET @StringToExecute = 'INSERT INTO #BlitzResults
8085 (CheckID,
8086 Priority,
8087 FindingsGroup,
8088 Finding,
8089 URL,
8090 Details)
8091 SELECT 10 AS CheckID,
8092 100 AS Priority,
8093 ''Performance'' AS FindingsGroup,
8094 ''Resource Governor Enabled'' AS Finding,
8095 ''http://BrentOzar.com/go/rg'' AS URL,
8096 (''Resource Governor is enabled. Queries may be throttled. Make sure you understand how the Classifier Function is configured.'') AS Details FROM sys.resource_governor_configuration WHERE is_enabled = 1'
8097 EXECUTE(@StringToExecute)
8098 END;
8099 END
8100
8101
8102 IF NOT EXISTS ( SELECT 1
8103 FROM #SkipChecks
8104 WHERE DatabaseName IS NULL AND CheckID = 11 )
8105 BEGIN
8106 IF @@VERSION NOT LIKE '%Microsoft SQL Server 2000%'
8107 BEGIN
8108 SET @StringToExecute = 'INSERT INTO #BlitzResults
8109 (CheckID,
8110 Priority,
8111 FindingsGroup,
8112 Finding,
8113 URL,
8114 Details)
8115 SELECT 11 AS CheckID,
8116 100 AS Priority,
8117 ''Performance'' AS FindingsGroup,
8118 ''Server Triggers Enabled'' AS Finding,
8119 ''http://BrentOzar.com/go/logontriggers/'' AS URL,
8120 (''Server Trigger ['' + [name] ++ ''] is enabled, so it runs every time someone logs in. Make sure you understand what that trigger is doing - the less work it does, the better.'') AS Details FROM sys.server_triggers WHERE is_disabled = 0 AND is_ms_shipped = 0'
8121 EXECUTE(@StringToExecute)
8122 END;
8123 END
8124
8125
8126 IF NOT EXISTS ( SELECT 1
8127 FROM #SkipChecks
8128 WHERE DatabaseName IS NULL AND CheckID = 12 )
8129 BEGIN
8130 INSERT INTO #BlitzResults
8131 ( CheckID ,
8132 DatabaseName ,
8133 Priority ,
8134 FindingsGroup ,
8135 Finding ,
8136 URL ,
8137 Details
8138 )
8139 SELECT 12 AS CheckID ,
8140 [name] AS DatabaseName ,
8141 10 AS Priority ,
8142 'Performance' AS FindingsGroup ,
8143 'Auto-Close Enabled' AS Finding ,
8144 'http://BrentOzar.com/go/autoclose' AS URL ,
8145 ( 'Database [' + [name]
8146 + '] has auto-close enabled. This setting can dramatically decrease performance.' ) AS Details
8147 FROM sys.databases
8148 WHERE is_auto_close_on = 1
8149 AND name NOT IN ( SELECT DISTINCT
8150 DatabaseName
8151 FROM #SkipChecks )
8152 END
8153
8154
8155 IF NOT EXISTS ( SELECT 1
8156 FROM #SkipChecks
8157 WHERE DatabaseName IS NULL AND CheckID = 13 )
8158 BEGIN
8159 INSERT INTO #BlitzResults
8160 ( CheckID ,
8161 DatabaseName ,
8162 Priority ,
8163 FindingsGroup ,
8164 Finding ,
8165 URL ,
8166 Details
8167 )
8168 SELECT 13 AS CheckID ,
8169 [name] AS DatabaseName ,
8170 10 AS Priority ,
8171 'Performance' AS FindingsGroup ,
8172 'Auto-Shrink Enabled' AS Finding ,
8173 'http://BrentOzar.com/go/autoshrink' AS URL ,
8174 ( 'Database [' + [name]
8175 + '] has auto-shrink enabled. This setting can dramatically decrease performance.' ) AS Details
8176 FROM sys.databases
8177 WHERE is_auto_shrink_on = 1
8178 AND name NOT IN ( SELECT DISTINCT
8179 DatabaseName
8180 FROM #SkipChecks );
8181 END
8182
8183
8184 IF NOT EXISTS ( SELECT 1
8185 FROM #SkipChecks
8186 WHERE DatabaseName IS NULL AND CheckID = 14 )
8187 BEGIN
8188 IF @@VERSION NOT LIKE '%Microsoft SQL Server 2000%'
8189 BEGIN
8190 SET @StringToExecute = 'INSERT INTO #BlitzResults
8191 (CheckID,
8192 DatabaseName,
8193 Priority,
8194 FindingsGroup,
8195 Finding,
8196 URL,
8197 Details)
8198 SELECT 14 AS CheckID,
8199 [name] as DatabaseName,
8200 50 AS Priority,
8201 ''Reliability'' AS FindingsGroup,
8202 ''Page Verification Not Optimal'' AS Finding,
8203 ''http://BrentOzar.com/go/torn'' AS URL,
8204 (''Database ['' + [name] + ''] has '' + [page_verify_option_desc] + '' for page verification. SQL Server may have a harder time recognizing and recovering from storage corruption. Consider using CHECKSUM instead.'') COLLATE database_default AS Details
8205 FROM sys.databases
8206 WHERE page_verify_option < 2
8207 AND name <> ''tempdb''
8208 and name not in (select distinct DatabaseName from #SkipChecks)'
8209 EXECUTE(@StringToExecute)
8210 END;
8211 END
8212
8213
8214 IF NOT EXISTS ( SELECT 1
8215 FROM #SkipChecks
8216 WHERE DatabaseName IS NULL AND CheckID = 15 )
8217 BEGIN
8218 INSERT INTO #BlitzResults
8219 ( CheckID ,
8220 DatabaseName ,
8221 Priority ,
8222 FindingsGroup ,
8223 Finding ,
8224 URL ,
8225 Details
8226 )
8227 SELECT 15 AS CheckID ,
8228 [name] AS DatabaseName ,
8229 110 AS Priority ,
8230 'Performance' AS FindingsGroup ,
8231 'Auto-Create Stats Disabled' AS Finding ,
8232 'http://BrentOzar.com/go/acs' AS URL ,
8233 ( 'Database [' + [name]
8234 + '] has auto-create-stats disabled. SQL Server uses statistics to build better execution plans, and without the ability to automatically create more, performance may suffer.' ) AS Details
8235 FROM sys.databases
8236 WHERE is_auto_create_stats_on = 0
8237 AND name NOT IN ( SELECT DISTINCT
8238 DatabaseName
8239 FROM #SkipChecks )
8240 END
8241
8242 IF NOT EXISTS ( SELECT 1
8243 FROM #SkipChecks
8244 WHERE DatabaseName IS NULL AND CheckID = 16 )
8245 BEGIN
8246 INSERT INTO #BlitzResults
8247 ( CheckID ,
8248 DatabaseName ,
8249 Priority ,
8250 FindingsGroup ,
8251 Finding ,
8252 URL ,
8253 Details
8254 )
8255 SELECT 16 AS CheckID ,
8256 [name] AS DatabaseName ,
8257 110 AS Priority ,
8258 'Performance' AS FindingsGroup ,
8259 'Auto-Update Stats Disabled' AS Finding ,
8260 'http://BrentOzar.com/go/aus' AS URL ,
8261 ( 'Database [' + [name]
8262 + '] has auto-update-stats disabled. SQL Server uses statistics to build better execution plans, and without the ability to automatically update them, performance may suffer.' ) AS Details
8263 FROM sys.databases
8264 WHERE is_auto_update_stats_on = 0
8265 AND name NOT IN ( SELECT DISTINCT
8266 DatabaseName
8267 FROM #SkipChecks )
8268 END
8269
8270
8271 IF NOT EXISTS ( SELECT 1
8272 FROM #SkipChecks
8273 WHERE DatabaseName IS NULL AND CheckID = 17 )
8274 BEGIN
8275 INSERT INTO #BlitzResults
8276 ( CheckID ,
8277 DatabaseName ,
8278 Priority ,
8279 FindingsGroup ,
8280 Finding ,
8281 URL ,
8282 Details
8283 )
8284 SELECT 17 AS CheckID ,
8285 [name] AS DatabaseName ,
8286 110 AS Priority ,
8287 'Performance' AS FindingsGroup ,
8288 'Stats Updated Asynchronously' AS Finding ,
8289 'http://BrentOzar.com/go/asyncstats' AS URL ,
8290 ( 'Database [' + [name]
8291 + '] has auto-update-stats-async enabled. When SQL Server gets a query for a table with out-of-date statistics, it will run the query with the stats it has - while updating stats to make later queries better. The initial run of the query may suffer, though.' ) AS Details
8292 FROM sys.databases
8293 WHERE is_auto_update_stats_async_on = 1
8294 AND name NOT IN ( SELECT DISTINCT
8295 DatabaseName
8296 FROM #SkipChecks )
8297 END
8298
8299
8300 IF NOT EXISTS ( SELECT 1
8301 FROM #SkipChecks
8302 WHERE DatabaseName IS NULL AND CheckID = 18 )
8303 BEGIN
8304 INSERT INTO #BlitzResults
8305 ( CheckID ,
8306 DatabaseName ,
8307 Priority ,
8308 FindingsGroup ,
8309 Finding ,
8310 URL ,
8311 Details
8312 )
8313 SELECT 18 AS CheckID ,
8314 [name] AS DatabaseName ,
8315 110 AS Priority ,
8316 'Performance' AS FindingsGroup ,
8317 'Forced Parameterization On' AS Finding ,
8318 'http://BrentOzar.com/go/forced' AS URL ,
8319 ( 'Database [' + [name]
8320 + '] has forced parameterization enabled. SQL Server will aggressively reuse query execution plans even if the applications do not parameterize their queries. This can be a performance booster with some programming languages, or it may use universally bad execution plans when better alternatives are available for certain parameters.' ) AS Details
8321 FROM sys.databases
8322 WHERE is_parameterization_forced = 1
8323 AND name NOT IN ( SELECT DatabaseName
8324 FROM #SkipChecks )
8325 END
8326
8327 IF NOT EXISTS ( SELECT 1
8328 FROM #SkipChecks
8329 WHERE DatabaseName IS NULL AND CheckID = 19 )
8330 BEGIN
8331 /* Method 1: Check sys.databases parameters */
8332 INSERT INTO #BlitzResults
8333 ( CheckID ,
8334 DatabaseName ,
8335 Priority ,
8336 FindingsGroup ,
8337 Finding ,
8338 URL ,
8339 Details
8340 )
8341
8342 SELECT 19 AS CheckID ,
8343 [name] AS DatabaseName ,
8344 200 AS Priority ,
8345 'Informational' AS FindingsGroup ,
8346 'Replication In Use' AS Finding ,
8347 'http://BrentOzar.com/go/repl' AS URL ,
8348 ( 'Database [' + [name]
8349 + '] is a replication publisher, subscriber, or distributor.' ) AS Details
8350 FROM sys.databases
8351 WHERE name NOT IN ( SELECT DISTINCT
8352 DatabaseName
8353 FROM #SkipChecks )
8354 AND is_published = 1
8355 OR is_subscribed = 1
8356 OR is_merge_published = 1
8357 OR is_distributor = 1;
8358
8359 /* Method B: check subscribers for MSreplication_objects tables */
8360 EXEC dbo.sp_MSforeachdb 'USE [?]; INSERT INTO #BlitzResults
8361 (CheckID,
8362 DatabaseName,
8363 Priority,
8364 FindingsGroup,
8365 Finding,
8366 URL,
8367 Details)
8368 SELECT DISTINCT 19,
8369 db_name(),
8370 200,
8371 ''Informational'',
8372 ''Replication In Use'',
8373 ''http://BrentOzar.com/go/repl'',
8374 (''['' + DB_NAME() + ''] has MSreplication_objects tables in it, indicating it is a replication subscriber.'')
8375 FROM [?].sys.tables
8376 WHERE name = ''dbo.MSreplication_objects'' AND ''?'' <> ''master''';
8377
8378 END
8379
8380 IF NOT EXISTS ( SELECT 1
8381 FROM #SkipChecks
8382 WHERE DatabaseName IS NULL AND CheckID = 20 )
8383 BEGIN
8384 INSERT INTO #BlitzResults
8385 ( CheckID ,
8386 DatabaseName ,
8387 Priority ,
8388 FindingsGroup ,
8389 Finding ,
8390 URL ,
8391 Details
8392 )
8393 SELECT 20 AS CheckID ,
8394 [name] AS DatabaseName ,
8395 110 AS Priority ,
8396 'Informational' AS FindingsGroup ,
8397 'Date Correlation On' AS Finding ,
8398 'http://BrentOzar.com/go/corr' AS URL ,
8399 ( 'Database [' + [name]
8400 + '] has date correlation enabled. This is not a default setting, and it has some performance overhead. It tells SQL Server that date fields in two tables are related, and SQL Server maintains statistics showing that relation.' ) AS Details
8401 FROM sys.databases
8402 WHERE is_date_correlation_on = 1
8403 AND name NOT IN ( SELECT DISTINCT
8404 DatabaseName
8405 FROM #SkipChecks )
8406 END
8407
8408
8409 IF NOT EXISTS ( SELECT 1
8410 FROM #SkipChecks
8411 WHERE DatabaseName IS NULL AND CheckID = 21 )
8412 BEGIN
8413 IF @@VERSION NOT LIKE '%Microsoft SQL Server 2000%'
8414 AND @@VERSION NOT LIKE '%Microsoft SQL Server 2005%'
8415 BEGIN
8416 SET @StringToExecute = 'INSERT INTO #BlitzResults
8417 (CheckID,
8418 DatabaseName,
8419 Priority,
8420 FindingsGroup,
8421 Finding,
8422 URL,
8423 Details)
8424 SELECT 21 AS CheckID,
8425 [name] as DatabaseName,
8426 20 AS Priority,
8427 ''Encryption'' AS FindingsGroup,
8428 ''Database Encrypted'' AS Finding,
8429 ''http://BrentOzar.com/go/tde'' AS URL,
8430 (''Database ['' + [name] + ''] has Transparent Data Encryption enabled. Make absolutely sure you have backed up the certificate and private key, or else you will not be able to restore this database.'') AS Details
8431 FROM sys.databases
8432 WHERE is_encrypted = 1
8433 and name not in (select distinct DatabaseName from #SkipChecks)'
8434 EXECUTE(@StringToExecute)
8435 END;
8436 END
8437
8438 /*
8439 Believe it or not, SQL Server doesn't track the default values
8440 for sp_configure options! We'll make our own list here.
8441 */
8442 INSERT INTO #ConfigurationDefaults
8443 VALUES ( 'access check cache bucket count', 0, 1001 );
8444 INSERT INTO #ConfigurationDefaults
8445 VALUES ( 'access check cache quota', 0, 1002 );
8446 INSERT INTO #ConfigurationDefaults
8447 VALUES ( 'Ad Hoc Distributed Queries', 0, 1003 );
8448 INSERT INTO #ConfigurationDefaults
8449 VALUES ( 'affinity I/O mask', 0, 1004 );
8450 INSERT INTO #ConfigurationDefaults
8451 VALUES ( 'affinity mask', 0, 1005 );
8452 INSERT INTO #ConfigurationDefaults
8453 VALUES ( 'Agent XPs', 0, 1006 );
8454 INSERT INTO #ConfigurationDefaults
8455 VALUES ( 'allow updates', 0, 1007 );
8456 INSERT INTO #ConfigurationDefaults
8457 VALUES ( 'awe enabled', 0, 1008 );
8458 INSERT INTO #ConfigurationDefaults
8459 VALUES ( 'blocked process threshold', 0, 1009 );
8460 INSERT INTO #ConfigurationDefaults
8461 VALUES ( 'c2 audit mode', 0, 1010 );
8462 INSERT INTO #ConfigurationDefaults
8463 VALUES ( 'clr enabled', 0, 1011 );
8464 INSERT INTO #ConfigurationDefaults
8465 VALUES ( 'cost threshold for parallelism', 5, 1012 );
8466 INSERT INTO #ConfigurationDefaults
8467 VALUES ( 'cross db ownership chaining', 0, 1013 );
8468 INSERT INTO #ConfigurationDefaults
8469 VALUES ( 'cursor threshold', -1, 1014 );
8470 INSERT INTO #ConfigurationDefaults
8471 VALUES ( 'Database Mail XPs', 0, 1015 );
8472 INSERT INTO #ConfigurationDefaults
8473 VALUES ( 'default full-text language', 1033, 1016 );
8474 INSERT INTO #ConfigurationDefaults
8475 VALUES ( 'default language', 0, 1017 );
8476 INSERT INTO #ConfigurationDefaults
8477 VALUES ( 'default trace enabled', 1, 1018 );
8478 INSERT INTO #ConfigurationDefaults
8479 VALUES ( 'disallow results from triggers', 0, 1019 );
8480 INSERT INTO #ConfigurationDefaults
8481 VALUES ( 'fill factor (%)', 0, 1020 );
8482 INSERT INTO #ConfigurationDefaults
8483 VALUES ( 'ft crawl bandwidth (max)', 100, 1021 );
8484 INSERT INTO #ConfigurationDefaults
8485 VALUES ( 'ft crawl bandwidth (min)', 0, 1022 );
8486 INSERT INTO #ConfigurationDefaults
8487 VALUES ( 'ft notify bandwidth (max)', 100, 1023 );
8488 INSERT INTO #ConfigurationDefaults
8489 VALUES ( 'ft notify bandwidth (min)', 0, 1024 );
8490 INSERT INTO #ConfigurationDefaults
8491 VALUES ( 'index create memory (KB)', 0, 1025 );
8492 INSERT INTO #ConfigurationDefaults
8493 VALUES ( 'in-doubt xact resolution', 0, 1026 );
8494 INSERT INTO #ConfigurationDefaults
8495 VALUES ( 'lightweight pooling', 0, 1027 );
8496 INSERT INTO #ConfigurationDefaults
8497 VALUES ( 'locks', 0, 1028 );
8498 INSERT INTO #ConfigurationDefaults
8499 VALUES ( 'max degree of parallelism', 0, 1029 );
8500 INSERT INTO #ConfigurationDefaults
8501 VALUES ( 'max full-text crawl range', 4, 1030 );
8502 INSERT INTO #ConfigurationDefaults
8503 VALUES ( 'max server memory (MB)', 2147483647, 1031 );
8504 INSERT INTO #ConfigurationDefaults
8505 VALUES ( 'max text repl size (B)', 65536, 1032 );
8506 INSERT INTO #ConfigurationDefaults
8507 VALUES ( 'max worker threads', 0, 1033 );
8508 INSERT INTO #ConfigurationDefaults
8509 VALUES ( 'media retention', 0, 1034 );
8510 INSERT INTO #ConfigurationDefaults
8511 VALUES ( 'min memory per query (KB)', 1024, 1035 );
8512 /* Accepting both 0 and 16 below because both have been seen in the wild as defaults. */
8513 IF EXISTS ( SELECT *
8514 FROM sys.configurations
8515 WHERE name = 'min server memory (MB)'
8516 AND value_in_use IN ( 0, 16 ) )
8517 INSERT INTO #ConfigurationDefaults
8518 SELECT 'min server memory (MB)' ,
8519 CAST(value_in_use AS BIGINT), 1036
8520 FROM sys.configurations
8521 WHERE name = 'min server memory (MB)'
8522 ELSE
8523 INSERT INTO #ConfigurationDefaults
8524 VALUES ( 'min server memory (MB)', 0, 1036 );
8525 INSERT INTO #ConfigurationDefaults
8526 VALUES ( 'nested triggers', 1, 1037 );
8527 INSERT INTO #ConfigurationDefaults
8528 VALUES ( 'network packet size (B)', 4096, 1038 );
8529 INSERT INTO #ConfigurationDefaults
8530 VALUES ( 'Ole Automation Procedures', 0, 1039 );
8531 INSERT INTO #ConfigurationDefaults
8532 VALUES ( 'open objects', 0, 1040 );
8533 INSERT INTO #ConfigurationDefaults
8534 VALUES ( 'optimize for ad hoc workloads', 0, 1041 );
8535 INSERT INTO #ConfigurationDefaults
8536 VALUES ( 'PH timeout (s)', 60, 1042 );
8537 INSERT INTO #ConfigurationDefaults
8538 VALUES ( 'precompute rank', 0, 1043 );
8539 INSERT INTO #ConfigurationDefaults
8540 VALUES ( 'priority boost', 0, 1044 );
8541 INSERT INTO #ConfigurationDefaults
8542 VALUES ( 'query governor cost limit', 0, 1045 );
8543 INSERT INTO #ConfigurationDefaults
8544 VALUES ( 'query wait (s)', -1, 1046 );
8545 INSERT INTO #ConfigurationDefaults
8546 VALUES ( 'recovery interval (min)', 0, 1047 );
8547 INSERT INTO #ConfigurationDefaults
8548 VALUES ( 'remote access', 1, 1048 );
8549 INSERT INTO #ConfigurationDefaults
8550 VALUES ( 'remote admin connections', 0, 1049 );
8551 INSERT INTO #ConfigurationDefaults
8552 VALUES ( 'remote proc trans', 0, 1050 );
8553 INSERT INTO #ConfigurationDefaults
8554 VALUES ( 'remote query timeout (s)', 600, 1051 );
8555 INSERT INTO #ConfigurationDefaults
8556 VALUES ( 'Replication XPs', 0, 1052 );
8557 INSERT INTO #ConfigurationDefaults
8558 VALUES ( 'RPC parameter data validation', 0, 1053 );
8559 INSERT INTO #ConfigurationDefaults
8560 VALUES ( 'scan for startup procs', 0, 1054 );
8561 INSERT INTO #ConfigurationDefaults
8562 VALUES ( 'server trigger recursion', 1, 1055 );
8563 INSERT INTO #ConfigurationDefaults
8564 VALUES ( 'set working set size', 0, 1056 );
8565 INSERT INTO #ConfigurationDefaults
8566 VALUES ( 'show advanced options', 0, 1057 );
8567 INSERT INTO #ConfigurationDefaults
8568 VALUES ( 'SMO and DMO XPs', 1, 1058 );
8569 INSERT INTO #ConfigurationDefaults
8570 VALUES ( 'SQL Mail XPs', 0, 1059 );
8571 INSERT INTO #ConfigurationDefaults
8572 VALUES ( 'transform noise words', 0, 1060 );
8573 INSERT INTO #ConfigurationDefaults
8574 VALUES ( 'two digit year cutoff', 2049, 1061 );
8575 INSERT INTO #ConfigurationDefaults
8576 VALUES ( 'user connections', 0, 1062 );
8577 INSERT INTO #ConfigurationDefaults
8578 VALUES ( 'user options', 0, 1063 );
8579 INSERT INTO #ConfigurationDefaults
8580 VALUES ( 'Web Assistant Procedures', 0, 1064 );
8581 INSERT INTO #ConfigurationDefaults
8582 VALUES ( 'xp_cmdshell', 0, 1065 );
8583 INSERT INTO #ConfigurationDefaults
8584 VALUES ( 'affinity64 mask', 0, 1066 );
8585 INSERT INTO #ConfigurationDefaults
8586 VALUES ( 'affinity64 I/O mask', 0, 1067 );
8587 INSERT INTO #ConfigurationDefaults
8588 VALUES ( 'contained database authentication', 0, 1068 );
8589 /* SQL Server 2012 also changes a configuration default */
8590 IF @@VERSION LIKE '%Microsoft SQL Server 2005%'
8591 OR @@VERSION LIKE '%Microsoft SQL Server 2008%'
8592 BEGIN
8593 INSERT INTO #ConfigurationDefaults
8594 VALUES ( 'remote login timeout (s)', 20, 1069 );
8595 END
8596 ELSE
8597 BEGIN
8598 INSERT INTO #ConfigurationDefaults
8599 VALUES ( 'remote login timeout (s)', 10, 1070 );
8600 END
8601
8602
8603 IF NOT EXISTS ( SELECT 1
8604 FROM #SkipChecks
8605 WHERE DatabaseName IS NULL AND CheckID = 22 )
8606 BEGIN
8607 INSERT INTO #BlitzResults
8608 ( CheckID ,
8609 Priority ,
8610 FindingsGroup ,
8611 Finding ,
8612 URL ,
8613 Details
8614 )
8615 SELECT cd.CheckID ,
8616 200 AS Priority ,
8617 'Non-Default Server Config' AS FindingsGroup ,
8618 cr.name AS Finding ,
8619 'http://BrentOzar.com/go/conf' AS URL ,
8620 ( 'This sp_configure option has been changed. Its default value is '
8621 + COALESCE(CAST(cd.[DefaultValue] AS VARCHAR(100)),
8622 '(unknown)')
8623 + ' and it has been set to '
8624 + CAST(cr.value_in_use AS VARCHAR(100))
8625 + '.' ) AS Details
8626 FROM sys.configurations cr
8627 INNER JOIN #ConfigurationDefaults cd ON cd.name = cr.name
8628 LEFT OUTER JOIN #ConfigurationDefaults cdUsed ON cdUsed.name = cr.name
8629 AND cdUsed.DefaultValue = cr.value_in_use
8630 WHERE cdUsed.name IS NULL;
8631 END
8632
8633
8634 IF NOT EXISTS ( SELECT 1
8635 FROM #SkipChecks
8636 WHERE DatabaseName IS NULL AND CheckID = 24 )
8637 BEGIN
8638 INSERT INTO #BlitzResults
8639 ( CheckID ,
8640 DatabaseName ,
8641 Priority ,
8642 FindingsGroup ,
8643 Finding ,
8644 URL ,
8645 Details
8646 )
8647 SELECT DISTINCT
8648 24 AS CheckID ,
8649 DB_NAME(database_id) AS DatabaseName ,
8650 20 AS Priority ,
8651 'Reliability' AS FindingsGroup ,
8652 'System Database on C Drive' AS Finding ,
8653 'http://BrentOzar.com/go/cdrive' AS URL ,
8654 ( 'The ' + DB_NAME(database_id)
8655 + ' database has a file on the C drive. Putting system databases on the C drive runs the risk of crashing the server when it runs out of space.' ) AS Details
8656 FROM sys.master_files
8657 WHERE UPPER(LEFT(physical_name, 1)) = 'C'
8658 AND DB_NAME(database_id) IN ( 'master',
8659 'model', 'msdb' );
8660 END
8661
8662
8663 IF NOT EXISTS ( SELECT 1
8664 FROM #SkipChecks
8665 WHERE DatabaseName IS NULL AND CheckID = 25 )
8666 BEGIN
8667 INSERT INTO #BlitzResults
8668 ( CheckID ,
8669 DatabaseName ,
8670 Priority ,
8671 FindingsGroup ,
8672 Finding ,
8673 URL ,
8674 Details
8675 )
8676 SELECT TOP 1
8677 25 AS CheckID ,
8678 'tempdb' ,
8679 100 AS Priority ,
8680 'Performance' AS FindingsGroup ,
8681 'TempDB on C Drive' AS Finding ,
8682 'http://BrentOzar.com/go/cdrive' AS URL ,
8683 CASE WHEN growth > 0
8684 THEN ( 'The tempdb database has files on the C drive. TempDB frequently grows unpredictably, putting your server at risk of running out of C drive space and crashing hard. C is also often much slower than other drives, so performance may be suffering.' )
8685 ELSE ( 'The tempdb database has files on the C drive. TempDB is not set to Autogrow, hopefully it is big enough. C is also often much slower than other drives, so performance may be suffering.' )
8686 END AS Details
8687 FROM sys.master_files
8688 WHERE UPPER(LEFT(physical_name, 1)) = 'C'
8689 AND DB_NAME(database_id) = 'tempdb';
8690 END
8691
8692
8693 IF NOT EXISTS ( SELECT 1
8694 FROM #SkipChecks
8695 WHERE DatabaseName IS NULL AND CheckID = 26 )
8696 BEGIN
8697 INSERT INTO #BlitzResults
8698 ( CheckID ,
8699 DatabaseName ,
8700 Priority ,
8701 FindingsGroup ,
8702 Finding ,
8703 URL ,
8704 Details
8705 )
8706 SELECT DISTINCT
8707 26 AS CheckID ,
8708 DB_NAME(database_id) AS DatabaseName ,
8709 20 AS Priority ,
8710 'Reliability' AS FindingsGroup ,
8711 'User Databases on C Drive' AS Finding ,
8712 'http://BrentOzar.com/go/cdrive' AS URL ,
8713 ( 'The ' + DB_NAME(database_id)
8714 + ' database has a file on the C drive. Putting databases on the C drive runs the risk of crashing the server when it runs out of space.' ) AS Details
8715 FROM sys.master_files
8716 WHERE UPPER(LEFT(physical_name, 1)) = 'C'
8717 AND DB_NAME(database_id) NOT IN ( 'master',
8718 'model', 'msdb',
8719 'tempdb' )
8720 AND DB_NAME(database_id) NOT IN (
8721 SELECT DISTINCT
8722 DatabaseName
8723 FROM #SkipChecks )
8724 END
8725
8726
8727 IF NOT EXISTS ( SELECT 1
8728 FROM #SkipChecks
8729 WHERE DatabaseName IS NULL AND CheckID = 27 )
8730 BEGIN
8731 INSERT INTO #BlitzResults
8732 ( CheckID ,
8733 DatabaseName ,
8734 Priority ,
8735 FindingsGroup ,
8736 Finding ,
8737 URL ,
8738 Details
8739 )
8740 SELECT 27 AS CheckID ,
8741 'master' AS DatabaseName ,
8742 200 AS Priority ,
8743 'Informational' AS FindingsGroup ,
8744 'Tables in the Master Database' AS Finding ,
8745 'http://BrentOzar.com/go/mastuser' AS URL ,
8746 ( 'The ' + name
8747 + ' table in the master database was created by end users on '
8748 + CAST(create_date AS VARCHAR(20))
8749 + '. Tables in the master database may not be restored in the event of a disaster.' ) AS Details
8750 FROM master.sys.tables
8751 WHERE is_ms_shipped = 0;
8752 END
8753
8754
8755 IF NOT EXISTS ( SELECT 1
8756 FROM #SkipChecks
8757 WHERE DatabaseName IS NULL AND CheckID = 28 )
8758 BEGIN
8759 INSERT INTO #BlitzResults
8760 ( CheckID ,
8761 Priority ,
8762 FindingsGroup ,
8763 Finding ,
8764 URL ,
8765 Details
8766 )
8767 SELECT 28 AS CheckID ,
8768 200 AS Priority ,
8769 'Informational' AS FindingsGroup ,
8770 'Tables in the MSDB Database' AS Finding ,
8771 'http://BrentOzar.com/go/msdbuser' AS URL ,
8772 ( 'The ' + name
8773 + ' table in the msdb database was created by end users on '
8774 + CAST(create_date AS VARCHAR(20))
8775 + '. Tables in the msdb database may not be restored in the event of a disaster.' ) AS Details
8776 FROM msdb.sys.tables
8777 WHERE is_ms_shipped = 0;
8778 END
8779
8780
8781 IF NOT EXISTS ( SELECT 1
8782 FROM #SkipChecks
8783 WHERE DatabaseName IS NULL AND CheckID = 29 )
8784 BEGIN
8785 INSERT INTO #BlitzResults
8786 ( CheckID ,
8787 Priority ,
8788 FindingsGroup ,
8789 Finding ,
8790 URL ,
8791 Details
8792 )
8793 SELECT 29 AS CheckID ,
8794 200 AS Priority ,
8795 'Informational' AS FindingsGroup ,
8796 'Tables in the Model Database' AS Finding ,
8797 'http://BrentOzar.com/go/model' AS URL ,
8798 ( 'The ' + name
8799 + ' table in the model database was created by end users on '
8800 + CAST(create_date AS VARCHAR(20))
8801 + '. Tables in the model database are automatically copied into all new databases.' ) AS Details
8802 FROM model.sys.tables
8803 WHERE is_ms_shipped = 0;
8804 END
8805
8806
8807 IF NOT EXISTS ( SELECT 1
8808 FROM #SkipChecks
8809 WHERE DatabaseName IS NULL AND CheckID = 30 )
8810 BEGIN
8811 IF ( SELECT COUNT(*)
8812 FROM msdb.dbo.sysalerts
8813 WHERE severity BETWEEN 19 AND 25
8814 ) < 7
8815 INSERT INTO #BlitzResults
8816 ( CheckID ,
8817 Priority ,
8818 FindingsGroup ,
8819 Finding ,
8820 URL ,
8821 Details
8822 )
8823 SELECT 30 AS CheckID ,
8824 50 AS Priority ,
8825 'Reliability' AS FindingsGroup ,
8826 'Not All Alerts Configured' AS Finding ,
8827 'http://BrentOzar.com/go/alert' AS URL ,
8828 ( 'Not all SQL Server Agent alerts have been configured. This is a free, easy way to get notified of corruption, job failures, or major outages even before monitoring systems pick it up.' ) AS Details;
8829 END
8830
8831
8832
8833 IF NOT EXISTS ( SELECT 1
8834 FROM #SkipChecks
8835 WHERE DatabaseName IS NULL AND CheckID = 59 )
8836 BEGIN
8837 IF EXISTS ( SELECT *
8838 FROM msdb.dbo.sysalerts
8839 WHERE enabled = 1
8840 AND COALESCE(has_notification, 0) = 0
8841 AND (job_id IS NULL OR job_id = 0x))
8842 INSERT INTO #BlitzResults
8843 ( CheckID ,
8844 Priority ,
8845 FindingsGroup ,
8846 Finding ,
8847 URL ,
8848 Details
8849 )
8850 SELECT 59 AS CheckID ,
8851 50 AS Priority ,
8852 'Reliability' AS FindingsGroup ,
8853 'Alerts Configured without Follow Up' AS Finding ,
8854 'http://BrentOzar.com/go/alert' AS URL ,
8855 ( 'SQL Server Agent alerts have been configured but they either do not notify anyone or else they do not take any action. This is a free, easy way to get notified of corruption, job failures, or major outages even before monitoring systems pick it up.' ) AS Details;
8856 END
8857
8858 IF NOT EXISTS ( SELECT 1
8859 FROM #SkipChecks
8860 WHERE DatabaseName IS NULL AND CheckID = 96 )
8861 BEGIN
8862 IF NOT EXISTS ( SELECT *
8863 FROM msdb.dbo.sysalerts
8864 WHERE message_id IN ( 823, 824, 825 ) )
8865 INSERT INTO #BlitzResults
8866 ( CheckID ,
8867 Priority ,
8868 FindingsGroup ,
8869 Finding ,
8870 URL ,
8871 Details
8872 )
8873 SELECT 96 AS CheckID ,
8874 50 AS Priority ,
8875 'Reliability' AS FindingsGroup ,
8876 'No Alerts for Corruption' AS Finding ,
8877 'http://BrentOzar.com/go/alert' AS URL ,
8878 ( 'SQL Server Agent alerts do not exist for errors 823, 824, and 825. These three errors can give you notification about early hardware failure. Enabling them can prevent you a lot of heartbreak.' ) AS Details;
8879 END
8880
8881
8882 IF NOT EXISTS ( SELECT 1
8883 FROM #SkipChecks
8884 WHERE DatabaseName IS NULL AND CheckID = 61 )
8885 BEGIN
8886 IF NOT EXISTS ( SELECT *
8887 FROM msdb.dbo.sysalerts
8888 WHERE severity BETWEEN 19 AND 25 )
8889 INSERT INTO #BlitzResults
8890 ( CheckID ,
8891 Priority ,
8892 FindingsGroup ,
8893 Finding ,
8894 URL ,
8895 Details
8896 )
8897 SELECT 61 AS CheckID ,
8898 50 AS Priority ,
8899 'Reliability' AS FindingsGroup ,
8900 'No Alerts for Sev 19-25' AS Finding ,
8901 'http://BrentOzar.com/go/alert' AS URL ,
8902 ( 'SQL Server Agent alerts do not exist for severity levels 19 through 25. These are some very severe SQL Server errors. Knowing that these are happening may let you recover from errors faster.' ) AS Details;
8903 END
8904
8905 --check for disabled alerts
8906 IF NOT EXISTS ( SELECT 1
8907 FROM #SkipChecks
8908 WHERE DatabaseName IS NULL AND CheckID = 98 )
8909 BEGIN
8910 IF EXISTS ( SELECT name
8911 FROM msdb.dbo.sysalerts
8912 WHERE enabled = 0 )
8913 INSERT INTO #BlitzResults
8914 ( CheckID ,
8915 Priority ,
8916 FindingsGroup ,
8917 Finding ,
8918 URL ,
8919 Details
8920 )
8921 SELECT 98 AS CheckID ,
8922 50 AS Priority ,
8923 'Reliability' AS FindingsGroup ,
8924 'Alerts Disabled' AS Finding ,
8925 'http://www.BrentOzar.com/go/alerts/' AS URL ,
8926 ( 'The following Alert is disabled, please review and enable if desired: '
8927 + name ) AS Details
8928 FROM msdb.dbo.sysalerts
8929 WHERE enabled = 0
8930 END
8931
8932
8933 IF NOT EXISTS ( SELECT 1
8934 FROM #SkipChecks
8935 WHERE DatabaseName IS NULL AND CheckID = 31 )
8936 BEGIN
8937 IF NOT EXISTS ( SELECT *
8938 FROM msdb.dbo.sysoperators
8939 WHERE enabled = 1 )
8940 INSERT INTO #BlitzResults
8941 ( CheckID ,
8942 Priority ,
8943 FindingsGroup ,
8944 Finding ,
8945 URL ,
8946 Details
8947 )
8948 SELECT 31 AS CheckID ,
8949 50 AS Priority ,
8950 'Reliability' AS FindingsGroup ,
8951 'No Operators Configured/Enabled' AS Finding ,
8952 'http://BrentOzar.com/go/op' AS URL ,
8953 ( 'No SQL Server Agent operators (emails) have been configured. This is a free, easy way to get notified of corruption, job failures, or major outages even before monitoring systems pick it up.' ) AS Details;
8954 END
8955
8956
8957 IF NOT EXISTS ( SELECT 1
8958 FROM #SkipChecks
8959 WHERE DatabaseName IS NULL AND CheckID = 33 )
8960 BEGIN
8961 IF @@VERSION NOT LIKE '%Microsoft SQL Server 2000%'
8962 AND @@VERSION NOT LIKE '%Microsoft SQL Server 2005%'
8963 BEGIN
8964 EXEC dbo.sp_MSforeachdb 'USE [?]; INSERT INTO #BlitzResults
8965 (CheckID,
8966 DatabaseName,
8967 Priority,
8968 FindingsGroup,
8969 Finding,
8970 URL,
8971 Details)
8972 SELECT DISTINCT 33,
8973 db_name(),
8974 200,
8975 ''Licensing'',
8976 ''Enterprise Edition Features In Use'',
8977 ''http://BrentOzar.com/go/ee'',
8978 (''The ['' + DB_NAME() + ''] database is using '' + feature_name + ''. If this database is restored onto a Standard Edition server, the restore will fail.'')
8979 FROM [?].sys.dm_db_persisted_sku_features';
8980 END;
8981 END
8982
8983 IF NOT EXISTS ( SELECT 1
8984 FROM #SkipChecks
8985 WHERE DatabaseName IS NULL AND CheckID = 34 )
8986 BEGIN
8987 IF EXISTS ( SELECT *
8988 FROM sys.all_objects
8989 WHERE name = 'dm_db_mirroring_auto_page_repair' )
8990 BEGIN
8991 SET @StringToExecute = 'INSERT INTO #BlitzResults
8992 (CheckID,
8993 DatabaseName,
8994 Priority,
8995 FindingsGroup,
8996 Finding,
8997 URL,
8998 Details)
8999 SELECT DISTINCT
9000 34 AS CheckID ,
9001 db.name ,
9002 1 AS Priority ,
9003 ''Corruption'' AS FindingsGroup ,
9004 ''Database Corruption Detected'' AS Finding ,
9005 ''http://BrentOzar.com/go/repair'' AS URL ,
9006 ( ''Database mirroring has automatically repaired at least one corrupt page in the last 30 days. For more information, query the DMV sys.dm_db_mirroring_auto_page_repair.'' ) AS Details
9007 FROM (SELECT rp2.database_id, rp2.modification_time
9008 FROM sys.dm_db_mirroring_auto_page_repair rp2
9009 WHERE rp2.[database_id] not in (
9010 SELECT db2.[database_id]
9011 FROM sys.databases as db2
9012 WHERE db2.[state] = 1
9013 ) ) as rp
9014 INNER JOIN master.sys.databases db ON rp.database_id = db.database_id
9015 WHERE rp.modification_time >= DATEADD(dd, -30, GETDATE()) ;'
9016 EXECUTE(@StringToExecute)
9017 END;
9018 END
9019
9020 IF NOT EXISTS ( SELECT 1
9021 FROM #SkipChecks
9022 WHERE DatabaseName IS NULL AND CheckID = 89 )
9023 BEGIN
9024 IF EXISTS ( SELECT *
9025 FROM sys.all_objects
9026 WHERE name = 'dm_hadr_auto_page_repair' )
9027 BEGIN
9028 SET @StringToExecute = 'INSERT INTO #BlitzResults
9029 (CheckID,
9030 DatabaseName,
9031 Priority,
9032 FindingsGroup,
9033 Finding,
9034 URL,
9035 Details)
9036 SELECT DISTINCT
9037 89 AS CheckID ,
9038 db.name ,
9039 1 AS Priority ,
9040 ''Corruption'' AS FindingsGroup ,
9041 ''Database Corruption Detected'' AS Finding ,
9042 ''http://BrentOzar.com/go/repair'' AS URL ,
9043 ( ''AlwaysOn has automatically repaired at least one corrupt page in the last 30 days. For more information, query the DMV sys.dm_hadr_auto_page_repair.'' ) AS Details
9044 FROM sys.dm_hadr_auto_page_repair rp
9045 INNER JOIN master.sys.databases db ON rp.database_id = db.database_id
9046 WHERE rp.modification_time >= DATEADD(dd, -30, GETDATE()) ;'
9047 EXECUTE(@StringToExecute)
9048 END;
9049 END
9050
9051
9052 IF NOT EXISTS ( SELECT 1
9053 FROM #SkipChecks
9054 WHERE DatabaseName IS NULL AND CheckID = 90 )
9055 BEGIN
9056 IF EXISTS ( SELECT *
9057 FROM msdb.sys.all_objects
9058 WHERE name = 'suspect_pages' )
9059 BEGIN
9060 SET @StringToExecute = 'INSERT INTO #BlitzResults
9061 (CheckID,
9062 DatabaseName,
9063 Priority,
9064 FindingsGroup,
9065 Finding,
9066 URL,
9067 Details)
9068 SELECT DISTINCT
9069 90 AS CheckID ,
9070 db.name ,
9071 1 AS Priority ,
9072 ''Corruption'' AS FindingsGroup ,
9073 ''Database Corruption Detected'' AS Finding ,
9074 ''http://BrentOzar.com/go/repair'' AS URL ,
9075 ( ''SQL Server has detected at least one corrupt page in the last 30 days. For more information, query the system table msdb.dbo.suspect_pages.'' ) AS Details
9076 FROM msdb.dbo.suspect_pages sp
9077 INNER JOIN master.sys.databases db ON sp.database_id = db.database_id
9078 WHERE sp.last_update_date >= DATEADD(dd, -30, GETDATE()) ;'
9079 EXECUTE(@StringToExecute)
9080 END;
9081 END
9082
9083
9084 IF NOT EXISTS ( SELECT 1
9085 FROM #SkipChecks
9086 WHERE DatabaseName IS NULL AND CheckID = 36 )
9087 BEGIN
9088 INSERT INTO #BlitzResults
9089 ( CheckID ,
9090 Priority ,
9091 FindingsGroup ,
9092 Finding ,
9093 URL ,
9094 Details
9095 )
9096 SELECT DISTINCT
9097 36 AS CheckID ,
9098 100 AS Priority ,
9099 'Performance' AS FindingsGroup ,
9100 'Slow Storage Reads on Drive '
9101 + UPPER(LEFT(mf.physical_name, 1)) AS Finding ,
9102 'http://BrentOzar.com/go/slow' AS URL ,
9103 'Reads are averaging longer than 100ms for at least one database on this drive. For specific database file speeds, run the query from the information link.' AS Details
9104 FROM sys.dm_io_virtual_file_stats(NULL, NULL)
9105 AS fs
9106 INNER JOIN sys.master_files AS mf ON fs.database_id = mf.database_id
9107 AND fs.[file_id] = mf.[file_id]
9108 WHERE ( io_stall_read_ms / ( 1.0 + num_of_reads ) ) > 100;
9109 END
9110
9111 IF NOT EXISTS ( SELECT 1
9112 FROM #SkipChecks
9113 WHERE DatabaseName IS NULL AND CheckID = 37 )
9114 BEGIN
9115 INSERT INTO #BlitzResults
9116 ( CheckID ,
9117 Priority ,
9118 FindingsGroup ,
9119 Finding ,
9120 URL ,
9121 Details
9122 )
9123 SELECT DISTINCT
9124 37 AS CheckID ,
9125 100 AS Priority ,
9126 'Performance' AS FindingsGroup ,
9127 'Slow Storage Writes on Drive '
9128 + UPPER(LEFT(mf.physical_name, 1)) AS Finding ,
9129 'http://BrentOzar.com/go/slow' AS URL ,
9130 'Writes are averaging longer than 20ms for at least one database on this drive. For specific database file speeds, run the query from the information link.' AS Details
9131 FROM sys.dm_io_virtual_file_stats(NULL, NULL)
9132 AS fs
9133 INNER JOIN sys.master_files AS mf ON fs.database_id = mf.database_id
9134 AND fs.[file_id] = mf.[file_id]
9135 WHERE ( io_stall_write_ms / ( 1.0
9136 + num_of_writes ) ) > 20;
9137 END
9138
9139 IF NOT EXISTS ( SELECT 1
9140 FROM #SkipChecks
9141 WHERE DatabaseName IS NULL AND CheckID = 40 )
9142 BEGIN
9143 IF ( SELECT COUNT(*)
9144 FROM tempdb.sys.database_files
9145 WHERE type_desc = 'ROWS'
9146 ) = 1
9147 BEGIN
9148 INSERT INTO #BlitzResults
9149 ( CheckID ,
9150 DatabaseName ,
9151 Priority ,
9152 FindingsGroup ,
9153 Finding ,
9154 URL ,
9155 Details
9156 )
9157 VALUES ( 40 ,
9158 'tempdb' ,
9159 100 ,
9160 'Performance' ,
9161 'TempDB Only Has 1 Data File' ,
9162 'http://BrentOzar.com/go/tempdb' ,
9163 'TempDB is only configured with one data file. More data files are usually required to alleviate SGAM contention.'
9164 );
9165 END;
9166 END
9167
9168 IF NOT EXISTS ( SELECT 1
9169 FROM #SkipChecks
9170 WHERE DatabaseName IS NULL AND CheckID = 41 )
9171 BEGIN
9172 EXEC dbo.sp_MSforeachdb 'use [?];
9173 INSERT INTO #BlitzResults
9174 (CheckID,
9175 DatabaseName,
9176 Priority,
9177 FindingsGroup,
9178 Finding,
9179 URL,
9180 Details)
9181 SELECT 41,
9182 ''?'',
9183 100,
9184 ''Performance'',
9185 ''Multiple Log Files on One Drive'',
9186 ''http://BrentOzar.com/go/manylogs'',
9187 (''The ['' + DB_NAME() + ''] database has multiple log files on the '' + LEFT(physical_name, 1) + '' drive. This is not a performance booster because log file access is sequential, not parallel.'')
9188 FROM [?].sys.database_files WHERE type_desc = ''LOG''
9189 AND ''?'' <> ''[tempdb]''
9190 GROUP BY LEFT(physical_name, 1)
9191 HAVING COUNT(*) > 1';
9192 END
9193
9194 IF NOT EXISTS ( SELECT 1
9195 FROM #SkipChecks
9196 WHERE DatabaseName IS NULL AND CheckID = 42 )
9197 BEGIN
9198 EXEC dbo.sp_MSforeachdb 'use [?];
9199 INSERT INTO #BlitzResults
9200 (CheckID,
9201 DatabaseName,
9202 Priority,
9203 FindingsGroup,
9204 Finding,
9205 URL,
9206 Details)
9207 SELECT DISTINCT 42,
9208 ''?'',
9209 100,
9210 ''Performance'',
9211 ''Uneven File Growth Settings in One Filegroup'',
9212 ''http://BrentOzar.com/go/grow'',
9213 (''The ['' + DB_NAME() + ''] database has multiple data files in one filegroup, but they are not all set up to grow in identical amounts. This can lead to uneven file activity inside the filegroup.'')
9214 FROM [?].sys.database_files
9215 WHERE type_desc = ''ROWS''
9216 GROUP BY data_space_id
9217 HAVING COUNT(DISTINCT growth) > 1 OR COUNT(DISTINCT is_percent_growth) > 1';
9218 END
9219
9220 IF NOT EXISTS ( SELECT 1
9221 FROM #SkipChecks
9222 WHERE DatabaseName IS NULL AND CheckID = 44 )
9223 BEGIN
9224 INSERT INTO #BlitzResults
9225 ( CheckID ,
9226 Priority ,
9227 FindingsGroup ,
9228 Finding ,
9229 URL ,
9230 Details
9231 )
9232 SELECT 44 AS CheckID ,
9233 110 AS Priority ,
9234 'Performance' AS FindingsGroup ,
9235 'Queries Forcing Order Hints' AS Finding ,
9236 'http://BrentOzar.com/go/hints' AS URL ,
9237 CAST(occurrence AS VARCHAR(10))
9238 + ' instances of order hinting have been recorded since restart. This means queries are bossing the SQL Server optimizer around, and if they don''t know what they''re doing, this can cause more harm than good. This can also explain why DBA tuning efforts aren''t working.' AS Details
9239 FROM sys.dm_exec_query_optimizer_info
9240 WHERE counter = 'order hint'
9241 AND occurrence > 1
9242 END
9243
9244 IF NOT EXISTS ( SELECT 1
9245 FROM #SkipChecks
9246 WHERE DatabaseName IS NULL AND CheckID = 45 )
9247 BEGIN
9248 INSERT INTO #BlitzResults
9249 ( CheckID ,
9250 Priority ,
9251 FindingsGroup ,
9252 Finding ,
9253 URL ,
9254 Details
9255 )
9256 SELECT 45 AS CheckID ,
9257 110 AS Priority ,
9258 'Performance' AS FindingsGroup ,
9259 'Queries Forcing Join Hints' AS Finding ,
9260 'http://BrentOzar.com/go/hints' AS URL ,
9261 CAST(occurrence AS VARCHAR(10))
9262 + ' instances of join hinting have been recorded since restart. This means queries are bossing the SQL Server optimizer around, and if they don''t know what they''re doing, this can cause more harm than good. This can also explain why DBA tuning efforts aren''t working.' AS Details
9263 FROM sys.dm_exec_query_optimizer_info
9264 WHERE counter = 'join hint'
9265 AND occurrence > 1
9266 END
9267
9268 IF NOT EXISTS ( SELECT 1
9269 FROM #SkipChecks
9270 WHERE DatabaseName IS NULL AND CheckID = 49 )
9271 BEGIN
9272 INSERT INTO #BlitzResults
9273 ( CheckID ,
9274 Priority ,
9275 FindingsGroup ,
9276 Finding ,
9277 URL ,
9278 Details
9279 )
9280 SELECT DISTINCT
9281 49 AS CheckID ,
9282 200 AS Priority ,
9283 'Informational' AS FindingsGroup ,
9284 'Linked Server Configured' AS Finding ,
9285 'http://BrentOzar.com/go/link' AS URL ,
9286 +CASE WHEN l.remote_name = 'sa'
9287 THEN s.data_source
9288 + ' is configured as a linked server. Check its security configuration as it is connecting with sa, because any user who queries it will get admin-level permissions.'
9289 ELSE s.data_source
9290 + ' is configured as a linked server. Check its security configuration to make sure it isn''t connecting with SA or some other bone-headed administrative login, because any user who queries it might get admin-level permissions.'
9291 END AS Details
9292 FROM sys.servers s
9293 INNER JOIN sys.linked_logins l ON s.server_id = l.server_id
9294 WHERE s.is_linked = 1
9295 END
9296
9297 IF NOT EXISTS ( SELECT 1
9298 FROM #SkipChecks
9299 WHERE DatabaseName IS NULL AND CheckID = 50 )
9300 BEGIN
9301 IF @@VERSION NOT LIKE '%Microsoft SQL Server 2000%'
9302 AND @@VERSION NOT LIKE '%Microsoft SQL Server 2005%'
9303 BEGIN
9304 SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
9305 SELECT 50 AS CheckID ,
9306 100 AS Priority ,
9307 ''Performance'' AS FindingsGroup ,
9308 ''Max Memory Set Too High'' AS Finding ,
9309 ''http://BrentOzar.com/go/max'' AS URL ,
9310 ''SQL Server max memory is set to ''
9311 + CAST(c.value_in_use AS VARCHAR(20))
9312 + '' megabytes, but the server only has ''
9313 + CAST(( CAST(m.total_physical_memory_kb AS BIGINT) / 1024 ) AS VARCHAR(20))
9314 + '' megabytes. SQL Server may drain the system dry of memory, and under certain conditions, this can cause Windows to swap to disk.'' AS Details
9315 FROM sys.dm_os_sys_memory m
9316 INNER JOIN sys.configurations c ON c.name = ''max server memory (MB)''
9317 WHERE CAST(m.total_physical_memory_kb AS BIGINT) < ( CAST(c.value_in_use AS BIGINT) * 1024 )'
9318 EXECUTE(@StringToExecute)
9319 END;
9320 END
9321
9322 IF NOT EXISTS ( SELECT 1
9323 FROM #SkipChecks
9324 WHERE DatabaseName IS NULL AND CheckID = 51 )
9325 BEGIN
9326 IF @@VERSION NOT LIKE '%Microsoft SQL Server 2000%'
9327 AND @@VERSION NOT LIKE '%Microsoft SQL Server 2005%'
9328 BEGIN
9329 SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
9330 SELECT 51 AS CheckID ,
9331 1 AS Priority ,
9332 ''Performance'' AS FindingsGroup ,
9333 ''Memory Dangerously Low'' AS Finding ,
9334 ''http://BrentOzar.com/go/max'' AS URL ,
9335 ''The server has '' + CAST(( CAST(m.total_physical_memory_kb AS BIGINT) / 1024 ) AS VARCHAR(20)) + '' megabytes of physical memory, but only '' + CAST(( CAST(m.available_physical_memory_kb AS BIGINT) / 1024 ) AS VARCHAR(20))
9336 + '' megabytes are available. As the server runs out of memory, there is danger of swapping to disk, which will kill performance.'' AS Details
9337 FROM sys.dm_os_sys_memory m
9338 WHERE CAST(m.available_physical_memory_kb AS BIGINT) < 262144'
9339 EXECUTE(@StringToExecute)
9340 END;
9341 END
9342
9343 IF NOT EXISTS ( SELECT 1
9344 FROM #SkipChecks
9345 WHERE DatabaseName IS NULL AND CheckID = 53 )
9346 BEGIN
9347 INSERT INTO #BlitzResults
9348 ( CheckID ,
9349 Priority ,
9350 FindingsGroup ,
9351 Finding ,
9352 URL ,
9353 Details
9354 )
9355 SELECT TOP 1
9356 53 AS CheckID ,
9357 200 AS Priority ,
9358 'High Availability' AS FindingsGroup ,
9359 'Cluster Node' AS Finding ,
9360 'http://BrentOzar.com/go/node' AS URL ,
9361 'This is a node in a cluster.' AS Details
9362 FROM sys.dm_os_cluster_nodes
9363 END
9364
9365 IF NOT EXISTS ( SELECT 1
9366 FROM #SkipChecks
9367 WHERE DatabaseName IS NULL AND CheckID = 55 )
9368 BEGIN
9369 INSERT INTO #BlitzResults
9370 ( CheckID ,
9371 DatabaseName ,
9372 Priority ,
9373 FindingsGroup ,
9374 Finding ,
9375 URL ,
9376 Details
9377 )
9378 SELECT 55 AS CheckID ,
9379 [name] AS DatabaseName ,
9380 200 AS Priority ,
9381 'Security' AS FindingsGroup ,
9382 'Database Owner <> SA' AS Finding ,
9383 'http://BrentOzar.com/go/owndb' AS URL ,
9384 ( 'Database name: ' + [name] + ' '
9385 + 'Owner name: ' + SUSER_SNAME(owner_sid) ) AS Details
9386 FROM sys.databases
9387 WHERE SUSER_SNAME(owner_sid) <> SUSER_SNAME(0x01)
9388 AND name NOT IN ( SELECT DISTINCT
9389 DatabaseName
9390 FROM #SkipChecks );
9391 END
9392
9393 IF NOT EXISTS ( SELECT 1
9394 FROM #SkipChecks
9395 WHERE DatabaseName IS NULL AND CheckID = 57 )
9396 BEGIN
9397 INSERT INTO #BlitzResults
9398 ( CheckID ,
9399 Priority ,
9400 FindingsGroup ,
9401 Finding ,
9402 URL ,
9403 Details
9404 )
9405 SELECT 57 AS CheckID ,
9406 10 AS Priority ,
9407 'Security' AS FindingsGroup ,
9408 'SQL Agent Job Runs at Startup' AS Finding ,
9409 'http://BrentOzar.com/go/startup' AS URL ,
9410 ( 'Job [' + j.name
9411 + '] runs automatically when SQL Server Agent starts up. Make sure you know exactly what this job is doing, because it could pose a security risk.' ) AS Details
9412 FROM msdb.dbo.sysschedules sched
9413 JOIN msdb.dbo.sysjobschedules jsched ON sched.schedule_id = jsched.schedule_id
9414 JOIN msdb.dbo.sysjobs j ON jsched.job_id = j.job_id
9415 WHERE sched.freq_type = 64;
9416 END
9417
9418 IF NOT EXISTS ( SELECT 1
9419 FROM #SkipChecks
9420 WHERE DatabaseName IS NULL AND CheckID = 58 )
9421 BEGIN
9422 INSERT INTO #BlitzResults
9423 ( CheckID ,
9424 DatabaseName ,
9425 Priority ,
9426 FindingsGroup ,
9427 Finding ,
9428 URL ,
9429 Details
9430 )
9431 SELECT 58 AS CheckID ,
9432 d.[name] AS DatabaseName ,
9433 200 AS Priority ,
9434 'Reliability' AS FindingsGroup ,
9435 'Database Collation Mismatch' AS Finding ,
9436 'http://BrentOzar.com/go/collate' AS URL ,
9437 ( 'Database ' + d.NAME + ' has collation '
9438 + d.collation_name
9439 + '; Server collation is '
9440 + CONVERT(VARCHAR(100), SERVERPROPERTY('collation')) ) AS Details
9441 FROM master.sys.databases d
9442 WHERE d.collation_name <> SERVERPROPERTY('collation')
9443 AND d.name NOT IN ( SELECT DISTINCT
9444 DatabaseName
9445 FROM #SkipChecks )
9446 AND d.name NOT LIKE 'ReportServer%'
9447 END
9448
9449 IF NOT EXISTS ( SELECT 1
9450 FROM #SkipChecks
9451 WHERE DatabaseName IS NULL AND CheckID = 82 )
9452 BEGIN
9453 EXEC sp_MSforeachdb 'use [?];
9454 INSERT INTO #BlitzResults
9455 (CheckID,
9456 DatabaseName,
9457 Priority,
9458 FindingsGroup,
9459 Finding,
9460 URL, Details)
9461 SELECT DISTINCT 82 AS CheckID,
9462 ''?'' as DatabaseName,
9463 100 AS Priority,
9464 ''Performance'' AS FindingsGroup,
9465 ''File growth set to percent'',
9466 ''http://brentozar.com/go/percentgrowth'' AS URL,
9467 ''The ['' + DB_NAME() + ''] database is using percent filegrowth settings. This can lead to out of control filegrowth.''
9468 FROM [?].sys.database_files
9469 WHERE is_percent_growth = 1 ';
9470 END
9471
9472 IF NOT EXISTS ( SELECT 1
9473 FROM #SkipChecks
9474 WHERE DatabaseName IS NULL AND CheckID = 97 )
9475 BEGIN
9476 INSERT INTO #BlitzResults
9477 ( CheckID ,
9478 Priority ,
9479 FindingsGroup ,
9480 Finding ,
9481 URL ,
9482 Details
9483 )
9484 SELECT 97 AS CheckID ,
9485 100 AS Priority ,
9486 'Performance' AS FindingsGroup ,
9487 'Unusual SQL Server Edition' AS Finding ,
9488 'http://BrentOzar.com/go/workgroup' AS URL ,
9489 ( 'This server is using '
9490 + CAST(SERVERPROPERTY('edition') AS VARCHAR(100))
9491 + ', which is capped at low amounts of CPU and memory.' ) AS Details
9492 WHERE CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) NOT LIKE '%Standard%'
9493 AND CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) NOT LIKE '%Enterprise%'
9494 AND CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) NOT LIKE '%Developer%'
9495 AND CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) NOT LIKE '%Business Intelligence%'
9496 END
9497
9498 IF NOT EXISTS ( SELECT 1
9499 FROM #SkipChecks
9500 WHERE DatabaseName IS NULL AND CheckID = 62 )
9501 BEGIN
9502 INSERT INTO #BlitzResults
9503 ( CheckID ,
9504 DatabaseName ,
9505 Priority ,
9506 FindingsGroup ,
9507 Finding ,
9508 URL ,
9509 Details
9510 )
9511 SELECT 62 AS CheckID ,
9512 [name] AS DatabaseName ,
9513 200 AS Priority ,
9514 'Performance' AS FindingsGroup ,
9515 'Old Compatibility Level' AS Finding ,
9516 'http://BrentOzar.com/go/compatlevel' AS URL ,
9517 ( 'Database ' + [name]
9518 + ' is compatibility level '
9519 + CAST(compatibility_level AS VARCHAR(20))
9520 + ', which may cause unwanted results when trying to run queries that have newer T-SQL features.' ) AS Details
9521 FROM sys.databases
9522 WHERE name NOT IN ( SELECT DISTINCT
9523 DatabaseName
9524 FROM #SkipChecks )
9525 AND compatibility_level <> ( SELECT
9526 compatibility_level
9527 FROM
9528 sys.databases
9529 WHERE
9530 [name] = 'model'
9531 )
9532 END
9533
9534 IF NOT EXISTS ( SELECT 1
9535 FROM #SkipChecks
9536 WHERE DatabaseName IS NULL AND CheckID = 94 )
9537 BEGIN
9538 INSERT INTO #BlitzResults
9539 ( CheckID ,
9540 Priority ,
9541 FindingsGroup ,
9542 Finding ,
9543 URL ,
9544 Details
9545 )
9546 SELECT 94 AS CheckID ,
9547 50 AS [Priority] ,
9548 'Reliability' AS FindingsGroup ,
9549 'Agent Jobs Without Failure Emails' AS Finding ,
9550 'http://BrentOzar.com/go/alerts' AS URL ,
9551 'The job ' + [name]
9552 + ' has not been set up to notify an operator if it fails.' AS Details
9553 FROM msdb.[dbo].[sysjobs] j
9554 INNER JOIN ( SELECT DISTINCT
9555 [job_id]
9556 FROM [msdb].[dbo].[sysjobschedules]
9557 WHERE next_run_date > 0
9558 ) s ON j.job_id = s.job_id
9559 WHERE j.enabled = 1
9560 AND j.notify_email_operator_id = 0
9561 AND j.notify_netsend_operator_id = 0
9562 AND j.notify_page_operator_id = 0
9563 AND j.category_id <> 100 /* Exclude SSRS category */
9564 END
9565
9566
9567 IF EXISTS ( SELECT 1
9568 FROM sys.configurations
9569 WHERE name = 'remote admin connections'
9570 AND value_in_use = 0 )
9571 AND NOT EXISTS ( SELECT 1
9572 FROM #SkipChecks
9573 WHERE DatabaseName IS NULL AND CheckID = 100 )
9574 BEGIN
9575 INSERT INTO #BlitzResults
9576 ( CheckID ,
9577 Priority ,
9578 FindingsGroup ,
9579 Finding ,
9580 URL ,
9581 Details
9582 )
9583 SELECT 100 AS CheckID ,
9584 50 AS Priority ,
9585 'Reliability' AS FindingGroup ,
9586 'Remote DAC Disabled' AS Finding ,
9587 'http://BrentOzar.com/go/dac' AS URL ,
9588 'Remote access to the Dedicated Admin Connection (DAC) is not enabled. The DAC can make remote troubleshooting much easier when SQL Server is unresponsive.'
9589 END
9590
9591
9592 IF EXISTS ( SELECT *
9593 FROM sys.dm_os_schedulers
9594 WHERE is_online = 0 )
9595 AND NOT EXISTS ( SELECT 1
9596 FROM #SkipChecks
9597 WHERE DatabaseName IS NULL AND CheckID = 101 )
9598 BEGIN
9599 INSERT INTO #BlitzResults
9600 ( CheckID ,
9601 Priority ,
9602 FindingsGroup ,
9603 Finding ,
9604 URL ,
9605 Details
9606 )
9607 SELECT 101 AS CheckID ,
9608 50 AS Priority ,
9609 'Performance' AS FindingGroup ,
9610 'CPU Schedulers Offline' AS Finding ,
9611 'http://BrentOzar.com/go/schedulers' AS URL ,
9612 'Some CPU cores are not accessible to SQL Server due to affinity masking or licensing problems.'
9613 END
9614
9615
9616 IF NOT EXISTS ( SELECT 1
9617 FROM #SkipChecks
9618 WHERE DatabaseName IS NULL AND CheckID = 110 )
9619 AND EXISTS (SELECT * FROM master.sys.all_objects WHERE name = 'dm_os_memory_nodes')
9620 BEGIN
9621 SET @StringToExecute = 'IF EXISTS (SELECT *
9622 FROM sys.dm_os_nodes n
9623 INNER JOIN sys.dm_os_memory_nodes m ON n.memory_node_id = m.memory_node_id
9624 WHERE n.node_state_desc = ''OFFLINE'')
9625 INSERT INTO #BlitzResults
9626 ( CheckID ,
9627 Priority ,
9628 FindingsGroup ,
9629 Finding ,
9630 URL ,
9631 Details
9632 )
9633 SELECT 110 AS CheckID ,
9634 50 AS Priority ,
9635 ''Performance'' AS FindingGroup ,
9636 ''Memory Nodes Offline'' AS Finding ,
9637 ''http://BrentOzar.com/go/schedulers'' AS URL ,
9638 ''Due to affinity masking or licensing problems, some of the memory may not be available.''';
9639 EXECUTE(@StringToExecute);
9640 END
9641
9642
9643 IF EXISTS ( SELECT *
9644 FROM sys.databases
9645 WHERE state > 1 )
9646 AND NOT EXISTS ( SELECT 1
9647 FROM #SkipChecks
9648 WHERE DatabaseName IS NULL AND CheckID = 102 )
9649 BEGIN
9650 INSERT INTO #BlitzResults
9651 ( CheckID ,
9652 DatabaseName ,
9653 Priority ,
9654 FindingsGroup ,
9655 Finding ,
9656 URL ,
9657 Details
9658 )
9659 SELECT 102 AS CheckID ,
9660 [name] ,
9661 20 AS Priority ,
9662 'Reliability' AS FindingGroup ,
9663 'Unusual Database State: ' + [state_desc] AS Finding ,
9664 'http://BrentOzar.com/go/repair' AS URL ,
9665 'This database may not be online.'
9666 FROM sys.databases
9667 WHERE state > 1
9668 END
9669
9670 IF EXISTS ( SELECT *
9671 FROM master.sys.extended_procedures )
9672 AND NOT EXISTS ( SELECT 1
9673 FROM #SkipChecks
9674 WHERE DatabaseName IS NULL AND CheckID = 105 )
9675 BEGIN
9676 INSERT INTO #BlitzResults
9677 ( CheckID ,
9678 DatabaseName ,
9679 Priority ,
9680 FindingsGroup ,
9681 Finding ,
9682 URL ,
9683 Details
9684 )
9685 SELECT 105 AS CheckID ,
9686 'master' ,
9687 50 AS Priority ,
9688 'Reliability' AS FindingGroup ,
9689 'Extended Stored Procedures in Master' AS Finding ,
9690 'http://BrentOzar.com/go/clr' AS URL ,
9691 'The [' + name
9692 + '] extended stored procedure is in the master database. CLR may be in use, and the master database now needs to be part of your backup/recovery planning.'
9693 FROM master.sys.extended_procedures
9694 END
9695
9696
9697
9698 IF NOT EXISTS ( SELECT 1
9699 FROM #SkipChecks
9700 WHERE DatabaseName IS NULL AND CheckID = 107 )
9701 BEGIN
9702 INSERT INTO #BlitzResults
9703 ( CheckID ,
9704 Priority ,
9705 FindingsGroup ,
9706 Finding ,
9707 URL ,
9708 Details
9709 )
9710 SELECT 107 AS CheckID ,
9711 100 AS Priority ,
9712 'Performance' AS FindingGroup ,
9713 'Poison Wait Detected: THREADPOOL' AS Finding ,
9714 'http://BrentOzar.com/go/poison' AS URL ,
9715 CAST(SUM([wait_time_ms]) AS VARCHAR(100)) + ' milliseconds of this wait have been recorded. This wait often indicates killer performance problems.'
9716 FROM sys.[dm_os_wait_stats]
9717 WHERE wait_type = 'THREADPOOL'
9718 GROUP BY wait_type
9719 HAVING SUM([wait_time_ms]) > (SELECT 5000 * datediff(HH,create_date,CURRENT_TIMESTAMP) AS hours_since_startup FROM sys.databases WHERE name='tempdb')
9720 END
9721
9722 IF NOT EXISTS ( SELECT 1
9723 FROM #SkipChecks
9724 WHERE DatabaseName IS NULL AND CheckID = 108 )
9725 BEGIN
9726 INSERT INTO #BlitzResults
9727 ( CheckID ,
9728 Priority ,
9729 FindingsGroup ,
9730 Finding ,
9731 URL ,
9732 Details
9733 )
9734 SELECT 108 AS CheckID ,
9735 100 AS Priority ,
9736 'Performance' AS FindingGroup ,
9737 'Poison Wait Detected: RESOURCE_SEMAPHORE' AS Finding ,
9738 'http://BrentOzar.com/go/poison' AS URL ,
9739 CAST(SUM([wait_time_ms]) AS VARCHAR(100)) + ' milliseconds of this wait have been recorded. This wait often indicates killer performance problems.'
9740 FROM sys.[dm_os_wait_stats]
9741 WHERE wait_type = 'RESOURCE_SEMAPHORE'
9742 GROUP BY wait_type
9743 HAVING SUM([wait_time_ms]) > (SELECT 5000 * datediff(HH,create_date,CURRENT_TIMESTAMP) AS hours_since_startup FROM sys.databases WHERE name='tempdb')
9744 END
9745
9746
9747 IF NOT EXISTS ( SELECT 1
9748 FROM #SkipChecks
9749 WHERE DatabaseName IS NULL AND CheckID = 109 )
9750 BEGIN
9751 INSERT INTO #BlitzResults
9752 ( CheckID ,
9753 Priority ,
9754 FindingsGroup ,
9755 Finding ,
9756 URL ,
9757 Details
9758 )
9759 SELECT 109 AS CheckID ,
9760 100 AS Priority ,
9761 'Performance' AS FindingGroup ,
9762 'Poison Wait Detected: RESOURCE_SEMAPHORE_QUERY_COMPILE' AS Finding ,
9763 'http://BrentOzar.com/go/poison' AS URL ,
9764 CAST(SUM([wait_time_ms]) AS VARCHAR(100)) + ' milliseconds of this wait have been recorded. This wait often indicates killer performance problems.'
9765 FROM sys.[dm_os_wait_stats]
9766 WHERE wait_type = 'RESOURCE_SEMAPHORE_QUERY_COMPILE'
9767 GROUP BY wait_type
9768 HAVING SUM([wait_time_ms]) > (SELECT 5000 * datediff(HH,create_date,CURRENT_TIMESTAMP) AS hours_since_startup FROM sys.databases WHERE name='tempdb')
9769 END
9770
9771
9772 IF NOT EXISTS ( SELECT 1
9773 FROM #SkipChecks
9774 WHERE DatabaseName IS NULL AND CheckID = 121 )
9775 BEGIN
9776 INSERT INTO #BlitzResults
9777 ( CheckID ,
9778 Priority ,
9779 FindingsGroup ,
9780 Finding ,
9781 URL ,
9782 Details
9783 )
9784 SELECT 121 AS CheckID ,
9785 100 AS Priority ,
9786 'Performance' AS FindingGroup ,
9787 'Poison Wait Detected: Serializable Locking' AS Finding ,
9788 'http://BrentOzar.com/go/serializable' AS URL ,
9789 CAST(SUM([wait_time_ms]) / 1000 AS VARCHAR(100)) + ' seconds of this wait have been recorded. Queries are forcing serial operation (one query at a time) with lock hints.'
9790 FROM sys.[dm_os_wait_stats]
9791 WHERE wait_type LIKE '%LCK%R%'
9792 GROUP BY wait_type
9793 HAVING SUM([wait_time_ms]) > (SELECT 5000 * datediff(HH,create_date,CURRENT_TIMESTAMP) AS hours_since_startup FROM sys.databases WHERE name='tempdb')
9794 END
9795
9796
9797
9798 IF NOT EXISTS ( SELECT 1
9799 FROM #SkipChecks
9800 WHERE DatabaseName IS NULL AND CheckID = 111 )
9801 BEGIN
9802 INSERT INTO #BlitzResults
9803 ( CheckID ,
9804 Priority ,
9805 FindingsGroup ,
9806 Finding ,
9807 DatabaseName ,
9808 URL ,
9809 Details
9810 )
9811 SELECT 111 AS CheckID ,
9812 50 AS Priority ,
9813 'Reliability' AS FindingGroup ,
9814 'Possibly Broken Log Shipping' AS Finding ,
9815 d.[name] ,
9816 'http://BrentOzar.com/go/shipping' AS URL ,
9817 d.[name] + ' is in a restoring state, but has not had a backup applied in the last two days. This is a possible indication of a broken transaction log shipping setup.'
9818 FROM [master].sys.databases d
9819 INNER JOIN [master].sys.database_mirroring dm ON d.database_id = dm.database_id
9820 AND dm.mirroring_role IS NULL
9821 WHERE ( d.[state] = 1
9822 OR (d.[state] = 0 AND d.[is_in_standby] = 1) )
9823 AND NOT EXISTS(SELECT * FROM msdb.dbo.restorehistory rh
9824 INNER JOIN msdb.dbo.backupset bs ON rh.backup_set_id = bs.backup_set_id
9825 WHERE d.[name] COLLATE SQL_Latin1_General_CP1_CI_AS = rh.destination_database_name COLLATE SQL_Latin1_General_CP1_CI_AS
9826 AND rh.restore_date >= DATEADD(dd, -2, GETDATE()))
9827
9828 END
9829
9830
9831 IF NOT EXISTS ( SELECT 1
9832 FROM #SkipChecks
9833 WHERE DatabaseName IS NULL AND CheckID = 112 )
9834 AND EXISTS (SELECT * FROM master.sys.all_objects WHERE name = 'change_tracking_databases')
9835 BEGIN
9836 SET @StringToExecute = 'INSERT INTO #BlitzResults
9837 (CheckID,
9838 Priority,
9839 FindingsGroup,
9840 Finding,
9841 URL,
9842 Details)
9843 SELECT 112 AS CheckID,
9844 100 AS Priority,
9845 ''Performance'' AS FindingsGroup,
9846 ''Change Tracking Enabled'' AS Finding,
9847 ''http://BrentOzar.com/go/tracking'' AS URL,
9848 ( d.[name] + '' has change tracking enabled. This is not a default setting, and it has some performance overhead. It keeps track of changes to rows in tables that have change tracking turned on.'' ) AS Details FROM sys.change_tracking_databases AS ctd INNER JOIN sys.databases AS d ON ctd.database_id = d.database_id';
9849 EXECUTE(@StringToExecute);
9850 END
9851
9852 IF NOT EXISTS ( SELECT 1
9853 FROM #SkipChecks
9854 WHERE DatabaseName IS NULL AND CheckID = 116 )
9855 BEGIN
9856 INSERT INTO #BlitzResults
9857 ( CheckID ,
9858 Priority ,
9859 FindingsGroup ,
9860 Finding ,
9861 URL ,
9862 Details
9863 )
9864 SELECT 116 AS CheckID ,
9865 200 AS Priority ,
9866 'Informational' AS FindingGroup ,
9867 'Backup Compression Default Off' AS Finding ,
9868 'http://BrentOzar.com/go/backup' AS URL ,
9869 'Backup compression is included with SQL Server 2008R2 & newer, even in Standard Edition. We recommend turning backup compression on by default so that ad-hoc backups will get compressed.'
9870 FROM sys.configurations
9871 WHERE configuration_id = 1579 AND CAST(value_in_use AS INT) = 0
9872
9873 END
9874
9875 IF NOT EXISTS ( SELECT 1
9876 FROM #SkipChecks
9877 WHERE DatabaseName IS NULL AND CheckID = 117 )
9878 AND EXISTS (SELECT * FROM master.sys.all_objects WHERE name = 'dm_exec_query_resource_semaphores')
9879 BEGIN
9880 SET @StringToExecute = 'IF 0 < (SELECT SUM([forced_grant_count]) FROM sys.dm_exec_query_resource_semaphores WHERE [forced_grant_count] IS NOT NULL)
9881 INSERT INTO #BlitzResults
9882 (CheckID,
9883 Priority,
9884 FindingsGroup,
9885 Finding,
9886 URL,
9887 Details)
9888 SELECT 117 AS CheckID,
9889 100 AS Priority,
9890 ''Performance'' AS FindingsGroup,
9891 ''Memory Pressure Affecting Queries'' AS Finding,
9892 ''http://BrentOzar.com/go/grants'' AS URL,
9893 CAST(SUM(forced_grant_count) AS NVARCHAR(100)) + '' forced grants reported in the DMV sys.dm_exec_query_resource_semaphores, indicating memory pressure has affected query runtimes.''
9894 FROM sys.dm_exec_query_resource_semaphores WHERE [forced_grant_count] IS NOT NULL;'
9895 EXECUTE(@StringToExecute);
9896 END
9897
9898
9899
9900 IF NOT EXISTS ( SELECT 1
9901 FROM #SkipChecks
9902 WHERE DatabaseName IS NULL AND CheckID = 124 )
9903 BEGIN
9904 INSERT INTO #BlitzResults
9905 (CheckID,
9906 Priority,
9907 FindingsGroup,
9908 Finding,
9909 URL,
9910 Details)
9911 SELECT 124, 100, 'Performance', 'Deadlocks Happening Daily', 'http://BrentOzar.com/go/deadlocks',
9912 CAST(p.cntr_value AS NVARCHAR(100)) + ' deadlocks have been recorded since startup.' AS Details
9913 FROM sys.dm_os_performance_counters p
9914 INNER JOIN sys.databases d ON d.name = 'tempdb'
9915 WHERE RTRIM(p.counter_name) = 'Number of Deadlocks/sec'
9916 AND RTRIM(p.instance_name) = '_Total'
9917 AND p.cntr_value > 0
9918 AND (1.0 * p.cntr_value / NULLIF(datediff(DD,create_date,CURRENT_TIMESTAMP),0)) > 10;
9919 END
9920
9921
9922 IF DATEADD(mi, -15, GETDATE()) < (SELECT TOP 1 creation_time FROM sys.dm_exec_query_stats ORDER BY creation_time)
9923 BEGIN
9924 INSERT INTO #BlitzResults
9925 (CheckID,
9926 Priority,
9927 FindingsGroup,
9928 Finding,
9929 URL,
9930 Details)
9931 SELECT TOP 1 125, 10, 'Performance', 'Plan Cache Erased Recently', 'http://BrentOzar.com/askbrent/plan-cache-erased-recently/',
9932 'The oldest query in the plan cache was created at ' + CAST(creation_time AS NVARCHAR(50)) + '. Someone ran DBCC FREEPROCCACHE, restarted SQL Server, or it is under horrific memory pressure.'
9933 FROM sys.dm_exec_query_stats WITH (NOLOCK)
9934 ORDER BY creation_time
9935 END;
9936
9937 IF EXISTS (SELECT * FROM sys.configurations WHERE name = 'priority boost' AND (value = 1 OR value_in_use = 1))
9938 BEGIN
9939 INSERT INTO #BlitzResults
9940 (CheckID,
9941 Priority,
9942 FindingsGroup,
9943 Finding,
9944 URL,
9945 Details)
9946 VALUES(126, 5, 'Reliability', 'Priority Boost Enabled', 'http://BrentOzar.com/go/priorityboost/',
9947 'Priority Boost sounds awesome, but it can actually cause your SQL Server to crash.')
9948 END;
9949
9950 IF EXISTS (select * from msdb.dbo.backupset WHERE database_name = 'ReportServerTempDB')
9951 BEGIN
9952 INSERT INTO #BlitzResults
9953 (CheckID,
9954 Priority,
9955 DatabaseName,
9956 FindingsGroup,
9957 Finding,
9958 URL,
9959 Details)
9960 VALUES(127, 200, 'ReportServerTempDB', 'Backup', 'Backing Up Unneeded Database', 'http://BrentOzar.com/go/reportservertempdb/',
9961 'This database is being backed up, but you probably do not need to. See the URL for more details on how to reconstruct it.')
9962 END;
9963
9964 IF NOT EXISTS ( SELECT 1
9965 FROM #SkipChecks
9966 WHERE DatabaseName IS NULL AND CheckID = 128 )
9967 BEGIN
9968
9969 IF (@ProductVersionMajor = 12 AND @ProductVersionMinor < 2000) OR
9970 (@ProductVersionMajor = 11 AND @ProductVersionMinor <= 2100) OR
9971 (@ProductVersionMajor = 10.5 AND @ProductVersionMinor <= 2500) OR
9972 (@ProductVersionMajor = 10 AND @ProductVersionMinor <= 4000) OR
9973 (@ProductVersionMajor = 9 AND @ProductVersionMinor <= 5000)
9974 BEGIN
9975 INSERT INTO #BlitzResults(CheckID, Priority, FindingsGroup, Finding, URL, Details)
9976 VALUES(128, 20, 'Reliability', 'Unsupported Build of SQL Server', 'http://BrentOzar.com/go/unsupported',
9977 'Version ' + CAST(@ProductVersionMajor AS VARCHAR(100)) + '.' + CAST(@ProductVersionMinor AS VARCHAR(100)) + ' is no longer supported by Microsoft. You need to apply a service pack.');
9978 END;
9979
9980 END;
9981
9982 IF NOT EXISTS ( SELECT 1
9983 FROM #SkipChecks
9984 WHERE DatabaseName IS NULL AND CheckID = 129 )
9985 BEGIN
9986 IF (@ProductVersionMajor = 11 AND @ProductVersionMinor >= 3000 AND @ProductVersionMinor <= 3436) OR
9987 (@ProductVersionMajor = 11 AND @ProductVersionMinor = 5058) OR
9988 (@ProductVersionMajor = 12 AND @ProductVersionMinor >= 2000 AND @ProductVersionMinor <= 2342)
9989 BEGIN
9990 INSERT INTO #BlitzResults(CheckID, Priority, FindingsGroup, Finding, URL, Details)
9991 VALUES(129, 20, 'Reliability', 'Dangerous Build of SQL Server', 'http://sqlperformance.com/2014/06/sql-indexes/hotfix-sql-2012-rebuilds',
9992 'There are dangerous known bugs with version ' + CAST(@ProductVersionMajor AS VARCHAR(100)) + '.' + CAST(@ProductVersionMinor AS VARCHAR(100)) + '. Check the URL for details and apply the right service pack or hotfix.');
9993 END;
9994
9995 END;
9996
9997 IF @CheckUserDatabaseObjects = 1
9998 BEGIN
9999
10000 IF NOT EXISTS ( SELECT 1
10001 FROM #SkipChecks
10002 WHERE DatabaseName IS NULL AND CheckID = 32 )
10003 BEGIN
10004 EXEC dbo.sp_MSforeachdb 'USE [?];
10005 INSERT INTO #BlitzResults
10006 (CheckID,
10007 DatabaseName,
10008 Priority,
10009 FindingsGroup,
10010 Finding,
10011 URL,
10012 Details)
10013 SELECT DISTINCT 32,
10014 ''?'',
10015 110,
10016 ''Performance'',
10017 ''Triggers on Tables'',
10018 ''http://BrentOzar.com/go/trig'',
10019 (''The ['' + DB_NAME() + ''] database has triggers on the '' + s.name + ''.'' + o.name + '' table.'')
10020 FROM [?].sys.triggers t INNER JOIN [?].sys.objects o ON t.parent_id = o.object_id
10021 INNER JOIN [?].sys.schemas s ON o.schema_id = s.schema_id WHERE t.is_ms_shipped = 0 AND DB_NAME() != ''ReportServer''';
10022 END
10023
10024 IF NOT EXISTS ( SELECT 1
10025 FROM #SkipChecks
10026 WHERE DatabaseName IS NULL AND CheckID = 38 )
10027 BEGIN
10028 EXEC dbo.sp_MSforeachdb 'USE [?];
10029 INSERT INTO #BlitzResults
10030 (CheckID,
10031 DatabaseName,
10032 Priority,
10033 FindingsGroup,
10034 Finding,
10035 URL,
10036 Details)
10037 SELECT DISTINCT 38,
10038 ''?'',
10039 110,
10040 ''Performance'',
10041 ''Active Tables Without Clustered Indexes'',
10042 ''http://BrentOzar.com/go/heaps'',
10043 (''The ['' + DB_NAME() + ''] database has heaps - tables without a clustered index - that are being actively queried.'')
10044 FROM [?].sys.indexes i INNER JOIN [?].sys.objects o ON i.object_id = o.object_id
10045 INNER JOIN [?].sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
10046 INNER JOIN sys.databases sd ON sd.name = ''?''
10047 LEFT OUTER JOIN [?].sys.dm_db_index_usage_stats ius ON i.object_id = ius.object_id AND i.index_id = ius.index_id AND ius.database_id = sd.database_id
10048 WHERE i.type_desc = ''HEAP'' AND COALESCE(ius.user_seeks, ius.user_scans, ius.user_lookups, ius.user_updates) IS NOT NULL
10049 AND sd.name <> ''tempdb'' AND o.is_ms_shipped = 0 AND o.type <> ''S''';
10050 END
10051
10052 IF NOT EXISTS ( SELECT 1
10053 FROM #SkipChecks
10054 WHERE DatabaseName IS NULL AND CheckID = 39 )
10055 BEGIN
10056 EXEC dbo.sp_MSforeachdb 'USE [?];
10057 INSERT INTO #BlitzResults
10058 (CheckID,
10059 DatabaseName,
10060 Priority,
10061 FindingsGroup,
10062 Finding,
10063 URL,
10064 Details)
10065 SELECT DISTINCT 39,
10066 ''?'',
10067 110,
10068 ''Performance'',
10069 ''Inactive Tables Without Clustered Indexes'',
10070 ''http://BrentOzar.com/go/heaps'',
10071 (''The ['' + DB_NAME() + ''] database has heaps - tables without a clustered index - that have not been queried since the last restart. These may be backup tables carelessly left behind.'')
10072 FROM [?].sys.indexes i INNER JOIN [?].sys.objects o ON i.object_id = o.object_id
10073 INNER JOIN [?].sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
10074 INNER JOIN sys.databases sd ON sd.name = ''?''
10075 LEFT OUTER JOIN [?].sys.dm_db_index_usage_stats ius ON i.object_id = ius.object_id AND i.index_id = ius.index_id AND ius.database_id = sd.database_id
10076 WHERE i.type_desc = ''HEAP'' AND COALESCE(ius.user_seeks, ius.user_scans, ius.user_lookups, ius.user_updates) IS NULL
10077 AND sd.name <> ''tempdb'' AND o.is_ms_shipped = 0 AND o.type <> ''S''';
10078 END
10079
10080 IF NOT EXISTS ( SELECT 1
10081 FROM #SkipChecks
10082 WHERE DatabaseName IS NULL AND CheckID = 46 )
10083 BEGIN
10084 EXEC dbo.sp_MSforeachdb 'USE [?];
10085 INSERT INTO #BlitzResults
10086 (CheckID,
10087 DatabaseName,
10088 Priority,
10089 FindingsGroup,
10090 Finding,
10091 URL,
10092 Details)
10093 SELECT 46,
10094 ''?'',
10095 100,
10096 ''Performance'',
10097 ''Leftover Fake Indexes From Wizards'',
10098 ''http://BrentOzar.com/go/hypo'',
10099 (''The index ['' + DB_NAME() + ''].['' + s.name + ''].['' + o.name + ''].['' + i.name + ''] is a leftover hypothetical index from the Index Tuning Wizard or Database Tuning Advisor. This index is not actually helping performance and should be removed.'')
10100 from [?].sys.indexes i INNER JOIN [?].sys.objects o ON i.object_id = o.object_id INNER JOIN [?].sys.schemas s ON o.schema_id = s.schema_id
10101 WHERE i.is_hypothetical = 1';
10102 END
10103
10104 IF NOT EXISTS ( SELECT 1
10105 FROM #SkipChecks
10106 WHERE DatabaseName IS NULL AND CheckID = 47 )
10107 BEGIN
10108 EXEC dbo.sp_MSforeachdb 'USE [?];
10109 INSERT INTO #BlitzResults
10110 (CheckID,
10111 DatabaseName,
10112 Priority,
10113 FindingsGroup,
10114 Finding,
10115 URL,
10116 Details)
10117 SELECT 47,
10118 ''?'',
10119 100,
10120 ''Performance'',
10121 ''Indexes Disabled'',
10122 ''http://BrentOzar.com/go/ixoff'',
10123 (''The index ['' + DB_NAME() + ''].['' + s.name + ''].['' + o.name + ''].['' + i.name + ''] is disabled. This index is not actually helping performance and should either be enabled or removed.'')
10124 from [?].sys.indexes i INNER JOIN [?].sys.objects o ON i.object_id = o.object_id INNER JOIN [?].sys.schemas s ON o.schema_id = s.schema_id
10125 WHERE i.is_disabled = 1';
10126 END
10127
10128
10129 IF NOT EXISTS ( SELECT 1
10130 FROM #SkipChecks
10131 WHERE DatabaseName IS NULL AND CheckID = 48 )
10132 BEGIN
10133 EXEC dbo.sp_MSforeachdb 'USE [?];
10134 INSERT INTO #BlitzResults
10135 (CheckID,
10136 DatabaseName,
10137 Priority,
10138 FindingsGroup,
10139 Finding,
10140 URL,
10141 Details)
10142 SELECT DISTINCT 48,
10143 ''?'',
10144 100,
10145 ''Performance'',
10146 ''Foreign Keys Not Trusted'',
10147 ''http://BrentOzar.com/go/trust'',
10148 (''The ['' + DB_NAME() + ''] database has foreign keys that were probably disabled, data was changed, and then the key was enabled again. Simply enabling the key is not enough for the optimizer to use this key - we have to alter the table using the WITH CHECK CHECK CONSTRAINT parameter.'')
10149 from [?].sys.foreign_keys i INNER JOIN [?].sys.objects o ON i.parent_object_id = o.object_id INNER JOIN [?].sys.schemas s ON o.schema_id = s.schema_id
10150 WHERE i.is_not_trusted = 1 AND i.is_not_for_replication = 0 AND i.is_disabled = 0';
10151 END
10152
10153 IF NOT EXISTS ( SELECT 1
10154 FROM #SkipChecks
10155 WHERE DatabaseName IS NULL AND CheckID = 56 )
10156 BEGIN
10157 EXEC dbo.sp_MSforeachdb 'USE [?];
10158 INSERT INTO #BlitzResults
10159 (CheckID,
10160 DatabaseName,
10161 Priority,
10162 FindingsGroup,
10163 Finding,
10164 URL,
10165 Details)
10166 SELECT 56,
10167 ''?'',
10168 100,
10169 ''Performance'',
10170 ''Check Constraint Not Trusted'',
10171 ''http://BrentOzar.com/go/trust'',
10172 (''The check constraint ['' + DB_NAME() + ''].['' + s.name + ''].['' + o.name + ''].['' + i.name + ''] is not trusted - meaning, it was disabled, data was changed, and then the constraint was enabled again. Simply enabling the constraint is not enough for the optimizer to use this constraint - we have to alter the table using the WITH CHECK CHECK CONSTRAINT parameter.'')
10173 from [?].sys.check_constraints i INNER JOIN [?].sys.objects o ON i.parent_object_id = o.object_id
10174 INNER JOIN [?].sys.schemas s ON o.schema_id = s.schema_id
10175 WHERE i.is_not_trusted = 1 AND i.is_not_for_replication = 0 AND i.is_disabled = 0';
10176 END
10177
10178 IF NOT EXISTS ( SELECT 1
10179 FROM #SkipChecks
10180 WHERE DatabaseName IS NULL AND CheckID = 95 )
10181 BEGIN
10182 IF @@VERSION NOT LIKE '%Microsoft SQL Server 2000%'
10183 AND @@VERSION NOT LIKE '%Microsoft SQL Server 2005%'
10184 BEGIN
10185 EXEC dbo.sp_MSforeachdb 'USE [?];
10186 INSERT INTO #BlitzResults
10187 (CheckID,
10188 DatabaseName,
10189 Priority,
10190 FindingsGroup,
10191 Finding,
10192 URL,
10193 Details)
10194 SELECT TOP 1 95 AS CheckID,
10195 ''?'' as DatabaseName,
10196 110 AS Priority,
10197 ''Performance'' AS FindingsGroup,
10198 ''Plan Guides Enabled'' AS Finding,
10199 ''http://BrentOzar.com/go/guides'' AS URL,
10200 (''Database ['' + DB_NAME() + ''] has query plan guides so a query will always get a specific execution plan. If you are having trouble getting query performance to improve, it might be due to a frozen plan. Review the DMV sys.plan_guides to learn more about the plan guides in place on this server.'') AS Details
10201 FROM [?].sys.plan_guides WHERE is_disabled = 0'
10202 END;
10203 END
10204
10205 IF NOT EXISTS ( SELECT 1
10206 FROM #SkipChecks
10207 WHERE DatabaseName IS NULL AND CheckID = 60 )
10208 BEGIN
10209 EXEC sp_MSforeachdb 'USE [?];
10210 INSERT INTO #BlitzResults
10211 (CheckID,
10212 DatabaseName,
10213 Priority,
10214 FindingsGroup,
10215 Finding,
10216 URL,
10217 Details)
10218 SELECT DISTINCT 60 AS CheckID,
10219 ''?'' as DatabaseName,
10220 100 AS Priority,
10221 ''Performance'' AS FindingsGroup,
10222 ''Fill Factor Changed'',
10223 ''http://brentozar.com/go/fillfactor'' AS URL,
10224 ''The ['' + DB_NAME() + ''] database has objects with fill factor < 80%. This can cause memory and storage performance problems, but may also prevent page splits.''
10225 FROM [?].sys.indexes
10226 WHERE fill_factor <> 0 AND fill_factor < 80 AND is_disabled = 0 AND is_hypothetical = 0';
10227 END
10228
10229 IF NOT EXISTS ( SELECT 1
10230 FROM #SkipChecks
10231 WHERE DatabaseName IS NULL AND CheckID = 78 )
10232 BEGIN
10233 EXEC dbo.sp_MSforeachdb 'USE [?];
10234 INSERT INTO #BlitzResults
10235 (CheckID,
10236 DatabaseName,
10237 Priority,
10238 FindingsGroup,
10239 Finding,
10240 URL,
10241 Details)
10242 SELECT 78,
10243 ''?'',
10244 100,
10245 ''Performance'',
10246 ''Stored Procedure WITH RECOMPILE'',
10247 ''http://BrentOzar.com/go/recompile'',
10248 (''['' + DB_NAME() + ''].['' + SPECIFIC_SCHEMA + ''].['' + SPECIFIC_NAME + ''] has WITH RECOMPILE in the stored procedure code, which may cause increased CPU usage due to constant recompiles of the code.'')
10249 from [?].INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_DEFINITION LIKE N''%WITH RECOMPILE%''';
10250 END
10251
10252 IF NOT EXISTS ( SELECT 1
10253 FROM #SkipChecks
10254 WHERE DatabaseName IS NULL AND CheckID = 86 )
10255 BEGIN
10256 EXEC dbo.sp_MSforeachdb 'USE [?]; INSERT INTO #BlitzResults (CheckID, DatabaseName, Priority, FindingsGroup, Finding, URL, Details) SELECT DISTINCT 86, DB_NAME(), 20, ''Security'', ''Elevated Permissions on a Database'', ''http://BrentOzar.com/go/elevated'', (''In ['' + DB_NAME() + ''], user ['' + u.name + ''] has the role ['' + g.name + '']. This user can perform tasks beyond just reading and writing data.'') FROM [?].dbo.sysmembers m inner join [?].dbo.sysusers u on m.memberuid = u.uid inner join sysusers g on m.groupuid = g.uid where u.name <> ''dbo'' and g.name in (''db_owner'' , ''db_accessAdmin'' , ''db_securityadmin'' , ''db_ddladmin'')';
10257 END
10258
10259
10260 /*Check for non-aligned indexes in partioned databases*/
10261
10262 IF NOT EXISTS ( SELECT 1
10263 FROM #SkipChecks
10264 WHERE DatabaseName IS NULL AND CheckID = 72 )
10265 BEGIN
10266 EXEC dbo.sp_MSforeachdb 'USE [?];
10267 insert into #partdb(dbname, objectname, type_desc)
10268 SELECT distinct db_name(DB_ID()) as DBName,o.name Object_Name,ds.type_desc
10269 FROM sys.objects AS o JOIN sys.indexes AS i ON o.object_id = i.object_id
10270 JOIN sys.data_spaces ds on ds.data_space_id = i.data_space_id
10271 LEFT OUTER JOIN sys.dm_db_index_usage_stats AS s ON i.object_id = s.object_id AND i.index_id = s.index_id AND s.database_id = DB_ID()
10272 WHERE o.type = ''u''
10273 -- Clustered and Non-Clustered indexes
10274 AND i.type IN (1, 2)
10275 AND o.object_id in
10276 (
10277 SELECT a.object_id from
10278 (SELECT ob.object_id, ds.type_desc from sys.objects ob JOIN sys.indexes ind on ind.object_id = ob.object_id join sys.data_spaces ds on ds.data_space_id = ind.data_space_id
10279 GROUP BY ob.object_id, ds.type_desc ) a group by a.object_id having COUNT (*) > 1
10280 )'
10281 INSERT INTO #BlitzResults
10282 ( CheckID ,
10283 DatabaseName ,
10284 Priority ,
10285 FindingsGroup ,
10286 Finding ,
10287 URL ,
10288 Details
10289 )
10290 SELECT DISTINCT
10291 72 AS CheckID ,
10292 dbname AS DatabaseName ,
10293 100 AS Priority ,
10294 'Performance' AS FindingsGroup ,
10295 'The partitioned database ' + dbname
10296 + ' may have non-aligned indexes' AS Finding ,
10297 'http://BrentOzar.com/go/aligned' AS URL ,
10298 'Having non-aligned indexes on partitioned tables may cause inefficient query plans and CPU pressure' AS Details
10299 FROM #partdb
10300 WHERE dbname IS NOT NULL
10301 AND dbname NOT IN ( SELECT DISTINCT
10302 DatabaseName
10303 FROM #SkipChecks )
10304 DROP TABLE #partdb
10305 END
10306
10307
10308 IF NOT EXISTS ( SELECT 1
10309 FROM #SkipChecks
10310 WHERE DatabaseName IS NULL AND CheckID = 113 )
10311 BEGIN
10312 EXEC dbo.sp_MSforeachdb 'USE [?];
10313 INSERT INTO #BlitzResults
10314 (CheckID,
10315 DatabaseName,
10316 Priority,
10317 FindingsGroup,
10318 Finding,
10319 URL,
10320 Details)
10321 SELECT DISTINCT 113,
10322 ''?'',
10323 50,
10324 ''Reliability'',
10325 ''Full Text Indexes Not Updating'',
10326 ''http://BrentOzar.com/go/fulltext'',
10327 (''At least one full text index in this database has not been crawled in the last week.'')
10328 from [?].sys.fulltext_indexes i WHERE i.is_enabled = 1 AND i.crawl_end_date < DATEADD(dd, -7, GETDATE())';
10329 END
10330
10331 IF NOT EXISTS ( SELECT 1
10332 FROM #SkipChecks
10333 WHERE DatabaseName IS NULL AND CheckID = 115 )
10334 BEGIN
10335 EXEC dbo.sp_MSforeachdb 'USE [?];
10336 INSERT INTO #BlitzResults
10337 (CheckID,
10338 DatabaseName,
10339 Priority,
10340 FindingsGroup,
10341 Finding,
10342 URL,
10343 Details)
10344 SELECT 115,
10345 ''?'',
10346 110,
10347 ''Performance'',
10348 ''Parallelism Rocket Surgery'',
10349 ''http://BrentOzar.com/go/makeparallel'',
10350 (''['' + DB_NAME() + ''] has a make_parallel function, indicating that an advanced developer may be manhandling SQL Server into forcing queries to go parallel.'')
10351 from [?].INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = ''make_parallel'' AND ROUTINE_TYPE = ''FUNCTION''';
10352 END
10353
10354
10355 IF NOT EXISTS ( SELECT 1
10356 FROM #SkipChecks
10357 WHERE DatabaseName IS NULL AND CheckID = 122 )
10358 BEGIN
10359 /* SQL Server 2012 and newer uses temporary stats for AlwaysOn Availability Groups, and those show up as user-created */
10360 IF EXISTS (SELECT *
10361 FROM sys.all_columns c
10362 INNER JOIN sys.all_objects o ON c.object_id = o.object_id
10363 WHERE c.name = 'is_temporary' AND o.name = 'stats')
10364
10365 EXEC dbo.sp_MSforeachdb 'USE [?];
10366 INSERT INTO #BlitzResults
10367 (CheckID,
10368 DatabaseName,
10369 Priority,
10370 FindingsGroup,
10371 Finding,
10372 URL,
10373 Details)
10374 SELECT TOP 1 122,
10375 ''?'',
10376 200,
10377 ''Performance'',
10378 ''User-Created Statistics In Place'',
10379 ''http://BrentOzar.com/go/userstats'',
10380 (''['' + DB_NAME() + ''] has user-created statistics. This indicates that someone is being a rocket scientist with the stats, and might actually be slowing things down, especially during stats updates.'')
10381 from [?].sys.stats WHERE user_created = 1 AND is_temporary = 0';
10382
10383 ELSE
10384 EXEC dbo.sp_MSforeachdb 'USE [?];
10385 INSERT INTO #BlitzResults
10386 (CheckID,
10387 DatabaseName,
10388 Priority,
10389 FindingsGroup,
10390 Finding,
10391 URL,
10392 Details)
10393 SELECT TOP 1 122,
10394 ''?'',
10395 200,
10396 ''Performance'',
10397 ''User-Created Statistics In Place'',
10398 ''http://BrentOzar.com/go/userstats'',
10399 (''['' + DB_NAME() + ''] has user-created statistics. This indicates that someone is being a rocket scientist with the stats, and might actually be slowing things down, especially during stats updates.'')
10400 from [?].sys.stats WHERE user_created = 1';
10401
10402
10403 END /* IF NOT EXISTS ( SELECT 1 */
10404
10405
10406 END /* IF @CheckUserDatabaseObjects = 1 */
10407
10408 IF @CheckProcedureCache = 1
10409 BEGIN
10410
10411 IF NOT EXISTS ( SELECT 1
10412 FROM #SkipChecks
10413 WHERE DatabaseName IS NULL AND CheckID = 35 )
10414 BEGIN
10415 INSERT INTO #BlitzResults
10416 ( CheckID ,
10417 Priority ,
10418 FindingsGroup ,
10419 Finding ,
10420 URL ,
10421 Details
10422 )
10423 SELECT 35 AS CheckID ,
10424 100 AS Priority ,
10425 'Performance' AS FindingsGroup ,
10426 'Single-Use Plans in Procedure Cache' AS Finding ,
10427 'http://BrentOzar.com/go/single' AS URL ,
10428 ( CAST(COUNT(*) AS VARCHAR(10))
10429 + ' query plans are taking up memory in the procedure cache. This may be wasted memory if we cache plans for queries that never get called again. This may be a good use case for SQL Server 2008''s Optimize for Ad Hoc or for Forced Parameterization.' ) AS Details
10430 FROM sys.dm_exec_cached_plans AS cp
10431 WHERE cp.usecounts = 1
10432 AND cp.objtype = 'Adhoc'
10433 AND EXISTS ( SELECT
10434 1
10435 FROM sys.configurations
10436 WHERE
10437 name = 'optimize for ad hoc workloads'
10438 AND value_in_use = 0 )
10439 HAVING COUNT(*) > 1;
10440 END
10441
10442
10443 /* Set up the cache tables. Different on 2005 since it doesn't support query_hash, query_plan_hash. */
10444 IF @@VERSION LIKE '%Microsoft SQL Server 2005%'
10445 BEGIN
10446 IF @CheckProcedureCacheFilter = 'CPU'
10447 OR @CheckProcedureCacheFilter IS NULL
10448 BEGIN
10449 SET @StringToExecute = 'WITH queries ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time])
10450 AS (SELECT TOP 20 qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time]
10451 FROM sys.dm_exec_query_stats qs
10452 ORDER BY qs.total_worker_time DESC)
10453 INSERT INTO #dm_exec_query_stats ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time])
10454 SELECT qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time]
10455 FROM queries qs
10456 LEFT OUTER JOIN #dm_exec_query_stats qsCaught ON qs.sql_handle = qsCaught.sql_handle AND qs.plan_handle = qsCaught.plan_handle AND qs.statement_start_offset = qsCaught.statement_start_offset
10457 WHERE qsCaught.sql_handle IS NULL;'
10458 EXECUTE(@StringToExecute)
10459 END
10460
10461 IF @CheckProcedureCacheFilter = 'Reads'
10462 OR @CheckProcedureCacheFilter IS NULL
10463 BEGIN
10464 SET @StringToExecute = 'WITH queries ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time])
10465 AS (SELECT TOP 20 qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time]
10466 FROM sys.dm_exec_query_stats qs
10467 ORDER BY qs.total_logical_reads DESC)
10468 INSERT INTO #dm_exec_query_stats ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time])
10469 SELECT qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time]
10470 FROM queries qs
10471 LEFT OUTER JOIN #dm_exec_query_stats qsCaught ON qs.sql_handle = qsCaught.sql_handle AND qs.plan_handle = qsCaught.plan_handle AND qs.statement_start_offset = qsCaught.statement_start_offset
10472 WHERE qsCaught.sql_handle IS NULL;'
10473 EXECUTE(@StringToExecute)
10474 END
10475
10476 IF @CheckProcedureCacheFilter = 'ExecCount'
10477 OR @CheckProcedureCacheFilter IS NULL
10478 BEGIN
10479 SET @StringToExecute = 'WITH queries ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time])
10480 AS (SELECT TOP 20 qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time]
10481 FROM sys.dm_exec_query_stats qs
10482 ORDER BY qs.execution_count DESC)
10483 INSERT INTO #dm_exec_query_stats ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time])
10484 SELECT qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time]
10485 FROM queries qs
10486 LEFT OUTER JOIN #dm_exec_query_stats qsCaught ON qs.sql_handle = qsCaught.sql_handle AND qs.plan_handle = qsCaught.plan_handle AND qs.statement_start_offset = qsCaught.statement_start_offset
10487 WHERE qsCaught.sql_handle IS NULL;'
10488 EXECUTE(@StringToExecute)
10489 END
10490
10491 IF @CheckProcedureCacheFilter = 'Duration'
10492 OR @CheckProcedureCacheFilter IS NULL
10493 BEGIN
10494 SET @StringToExecute = 'WITH queries ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time])
10495 AS (SELECT TOP 20 qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time]
10496 FROM sys.dm_exec_query_stats qs
10497 ORDER BY qs.total_elapsed_time DESC)
10498 INSERT INTO #dm_exec_query_stats ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time])
10499 SELECT qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time]
10500 FROM queries qs
10501 LEFT OUTER JOIN #dm_exec_query_stats qsCaught ON qs.sql_handle = qsCaught.sql_handle AND qs.plan_handle = qsCaught.plan_handle AND qs.statement_start_offset = qsCaught.statement_start_offset
10502 WHERE qsCaught.sql_handle IS NULL;'
10503 EXECUTE(@StringToExecute)
10504 END
10505
10506 END;
10507 IF @@VERSION LIKE '%Microsoft SQL Server 2008%'
10508 OR @@VERSION LIKE '%Microsoft SQL Server 2012%'
10509 OR @@VERSION LIKE '%Microsoft SQL Server 2014%'
10510 BEGIN
10511 IF @CheckProcedureCacheFilter = 'CPU'
10512 OR @CheckProcedureCacheFilter IS NULL
10513 BEGIN
10514 SET @StringToExecute = 'WITH queries ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time],[query_hash],[query_plan_hash])
10515 AS (SELECT TOP 20 qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time],qs.[query_hash],qs.[query_plan_hash]
10516 FROM sys.dm_exec_query_stats qs
10517 ORDER BY qs.total_worker_time DESC)
10518 INSERT INTO #dm_exec_query_stats ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time],[query_hash],[query_plan_hash])
10519 SELECT qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time],qs.[query_hash],qs.[query_plan_hash]
10520 FROM queries qs
10521 LEFT OUTER JOIN #dm_exec_query_stats qsCaught ON qs.sql_handle = qsCaught.sql_handle AND qs.plan_handle = qsCaught.plan_handle AND qs.statement_start_offset = qsCaught.statement_start_offset
10522 WHERE qsCaught.sql_handle IS NULL;'
10523 EXECUTE(@StringToExecute)
10524 END
10525
10526 IF @CheckProcedureCacheFilter = 'Reads'
10527 OR @CheckProcedureCacheFilter IS NULL
10528 BEGIN
10529 SET @StringToExecute = 'WITH queries ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time],[query_hash],[query_plan_hash])
10530 AS (SELECT TOP 20 qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time],qs.[query_hash],qs.[query_plan_hash]
10531 FROM sys.dm_exec_query_stats qs
10532 ORDER BY qs.total_logical_reads DESC)
10533 INSERT INTO #dm_exec_query_stats ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time],[query_hash],[query_plan_hash])
10534 SELECT qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time],qs.[query_hash],qs.[query_plan_hash]
10535 FROM queries qs
10536 LEFT OUTER JOIN #dm_exec_query_stats qsCaught ON qs.sql_handle = qsCaught.sql_handle AND qs.plan_handle = qsCaught.plan_handle AND qs.statement_start_offset = qsCaught.statement_start_offset
10537 WHERE qsCaught.sql_handle IS NULL;'
10538 EXECUTE(@StringToExecute)
10539 END
10540
10541 IF @CheckProcedureCacheFilter = 'ExecCount'
10542 OR @CheckProcedureCacheFilter IS NULL
10543 BEGIN
10544 SET @StringToExecute = 'WITH queries ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time],[query_hash],[query_plan_hash])
10545 AS (SELECT TOP 20 qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time],qs.[query_hash],qs.[query_plan_hash]
10546 FROM sys.dm_exec_query_stats qs
10547 ORDER BY qs.execution_count DESC)
10548 INSERT INTO #dm_exec_query_stats ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time],[query_hash],[query_plan_hash])
10549 SELECT qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time],qs.[query_hash],qs.[query_plan_hash]
10550 FROM queries qs
10551 LEFT OUTER JOIN #dm_exec_query_stats qsCaught ON qs.sql_handle = qsCaught.sql_handle AND qs.plan_handle = qsCaught.plan_handle AND qs.statement_start_offset = qsCaught.statement_start_offset
10552 WHERE qsCaught.sql_handle IS NULL;'
10553 EXECUTE(@StringToExecute)
10554 END
10555
10556 IF @CheckProcedureCacheFilter = 'Duration'
10557 OR @CheckProcedureCacheFilter IS NULL
10558 BEGIN
10559 SET @StringToExecute = 'WITH queries ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time],[query_hash],[query_plan_hash])
10560 AS (SELECT TOP 20 qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time],qs.[query_hash],qs.[query_plan_hash]
10561 FROM sys.dm_exec_query_stats qs
10562 ORDER BY qs.total_elapsed_time DESC)
10563 INSERT INTO #dm_exec_query_stats ([sql_handle],[statement_start_offset],[statement_end_offset],[plan_generation_num],[plan_handle],[creation_time],[last_execution_time],[execution_count],[total_worker_time],[last_worker_time],[min_worker_time],[max_worker_time],[total_physical_reads],[last_physical_reads],[min_physical_reads],[max_physical_reads],[total_logical_writes],[last_logical_writes],[min_logical_writes],[max_logical_writes],[total_logical_reads],[last_logical_reads],[min_logical_reads],[max_logical_reads],[total_clr_time],[last_clr_time],[min_clr_time],[max_clr_time],[total_elapsed_time],[last_elapsed_time],[min_elapsed_time],[max_elapsed_time],[query_hash],[query_plan_hash])
10564 SELECT qs.[sql_handle],qs.[statement_start_offset],qs.[statement_end_offset],qs.[plan_generation_num],qs.[plan_handle],qs.[creation_time],qs.[last_execution_time],qs.[execution_count],qs.[total_worker_time],qs.[last_worker_time],qs.[min_worker_time],qs.[max_worker_time],qs.[total_physical_reads],qs.[last_physical_reads],qs.[min_physical_reads],qs.[max_physical_reads],qs.[total_logical_writes],qs.[last_logical_writes],qs.[min_logical_writes],qs.[max_logical_writes],qs.[total_logical_reads],qs.[last_logical_reads],qs.[min_logical_reads],qs.[max_logical_reads],qs.[total_clr_time],qs.[last_clr_time],qs.[min_clr_time],qs.[max_clr_time],qs.[total_elapsed_time],qs.[last_elapsed_time],qs.[min_elapsed_time],qs.[max_elapsed_time],qs.[query_hash],qs.[query_plan_hash]
10565 FROM queries qs
10566 LEFT OUTER JOIN #dm_exec_query_stats qsCaught ON qs.sql_handle = qsCaught.sql_handle AND qs.plan_handle = qsCaught.plan_handle AND qs.statement_start_offset = qsCaught.statement_start_offset
10567 WHERE qsCaught.sql_handle IS NULL;'
10568 EXECUTE(@StringToExecute)
10569 END
10570
10571 /* Populate the query_plan_filtered field. Only works in 2005SP2+, but we're just doing it in 2008 to be safe. */
10572 UPDATE #dm_exec_query_stats
10573 SET query_plan_filtered = qp.query_plan
10574 FROM #dm_exec_query_stats qs
10575 CROSS APPLY sys.dm_exec_text_query_plan(qs.plan_handle,
10576 qs.statement_start_offset,
10577 qs.statement_end_offset)
10578 AS qp
10579
10580 END;
10581
10582 /* Populate the additional query_plan, text, and text_filtered fields */
10583 UPDATE #dm_exec_query_stats
10584 SET query_plan = qp.query_plan ,
10585 [text] = st.[text] ,
10586 text_filtered = SUBSTRING(st.text,
10587 ( qs.statement_start_offset
10588 / 2 ) + 1,
10589 ( ( CASE qs.statement_end_offset
10590 WHEN -1
10591 THEN DATALENGTH(st.text)
10592 ELSE qs.statement_end_offset
10593 END
10594 - qs.statement_start_offset )
10595 / 2 ) + 1)
10596 FROM #dm_exec_query_stats qs
10597 CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
10598 CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle)
10599 AS qp
10600
10601 /* Dump instances of our own script. We're not trying to tune ourselves. */
10602 DELETE #dm_exec_query_stats
10603 WHERE text LIKE '%sp_Blitz%'
10604 OR text LIKE '%#BlitzResults%'
10605
10606 /* Look for implicit conversions */
10607
10608 IF NOT EXISTS ( SELECT 1
10609 FROM #SkipChecks
10610 WHERE DatabaseName IS NULL AND CheckID = 63 )
10611 BEGIN
10612 INSERT INTO #BlitzResults
10613 ( CheckID ,
10614 Priority ,
10615 FindingsGroup ,
10616 Finding ,
10617 URL ,
10618 Details ,
10619 QueryPlan ,
10620 QueryPlanFiltered
10621 )
10622 SELECT 63 AS CheckID ,
10623 120 AS Priority ,
10624 'Query Plans' AS FindingsGroup ,
10625 'Implicit Conversion' AS Finding ,
10626 'http://BrentOzar.com/go/implicit' AS URL ,
10627 ( 'One of the top resource-intensive queries is comparing two fields that are not the same datatype.' ) AS Details ,
10628 qs.query_plan ,
10629 qs.query_plan_filtered
10630 FROM #dm_exec_query_stats qs
10631 WHERE COALESCE(qs.query_plan_filtered,
10632 CAST(qs.query_plan AS NVARCHAR(MAX))) LIKE '%CONVERT_IMPLICIT%'
10633 AND COALESCE(qs.query_plan_filtered,
10634 CAST(qs.query_plan AS NVARCHAR(MAX))) LIKE '%PhysicalOp="Index Scan"%'
10635 END
10636
10637 IF NOT EXISTS ( SELECT 1
10638 FROM #SkipChecks
10639 WHERE DatabaseName IS NULL AND CheckID = 64 )
10640 BEGIN
10641 INSERT INTO #BlitzResults
10642 ( CheckID ,
10643 Priority ,
10644 FindingsGroup ,
10645 Finding ,
10646 URL ,
10647 Details ,
10648 QueryPlan ,
10649 QueryPlanFiltered
10650 )
10651 SELECT 64 AS CheckID ,
10652 120 AS Priority ,
10653 'Query Plans' AS FindingsGroup ,
10654 'Implicit Conversion Affecting Cardinality' AS Finding ,
10655 'http://BrentOzar.com/go/implicit' AS URL ,
10656 ( 'One of the top resource-intensive queries has an implicit conversion that is affecting cardinality estimation.' ) AS Details ,
10657 qs.query_plan ,
10658 qs.query_plan_filtered
10659 FROM #dm_exec_query_stats qs
10660 WHERE COALESCE(qs.query_plan_filtered,
10661 CAST(qs.query_plan AS NVARCHAR(MAX))) LIKE '%<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT%'
10662 END
10663
10664 /* @cms4j, 29.11.2013: Look for RID or Key Lookups */
10665 IF NOT EXISTS ( SELECT 1
10666 FROM #SkipChecks
10667 WHERE DatabaseName IS NULL AND CheckID = 118 )
10668 BEGIN
10669 INSERT INTO #BlitzResults
10670 ( CheckID ,
10671 Priority ,
10672 FindingsGroup ,
10673 Finding ,
10674 URL ,
10675 Details ,
10676 QueryPlan ,
10677 QueryPlanFiltered
10678 )
10679 SELECT 118 AS CheckID ,
10680 120 AS Priority ,
10681 'Query Plans' AS FindingsGroup ,
10682 'RID or Key Lookups' AS Finding ,
10683 'http://BrentOzar.com/go/lookup' AS URL ,
10684 'One of the top resource-intensive queries contains RID or Key Lookups. Try to avoid them by creating covering indexes.' AS Details ,
10685 qs.query_plan ,
10686 qs.query_plan_filtered
10687 FROM #dm_exec_query_stats qs
10688 WHERE COALESCE(qs.query_plan_filtered,
10689 CAST(qs.query_plan AS NVARCHAR(MAX))) LIKE '%Lookup="1"%'
10690 END /* @cms4j, 29.11.2013: Look for RID or Key Lookups */
10691
10692
10693 /* Look for missing indexes */
10694 IF NOT EXISTS ( SELECT 1
10695 FROM #SkipChecks
10696 WHERE DatabaseName IS NULL AND CheckID = 65 )
10697 BEGIN
10698 INSERT INTO #BlitzResults
10699 ( CheckID ,
10700 Priority ,
10701 FindingsGroup ,
10702 Finding ,
10703 URL ,
10704 Details ,
10705 QueryPlan ,
10706 QueryPlanFiltered
10707 )
10708 SELECT 65 AS CheckID ,
10709 120 AS Priority ,
10710 'Query Plans' AS FindingsGroup ,
10711 'Missing Index' AS Finding ,
10712 'http://BrentOzar.com/go/missingindex' AS URL ,
10713 ( 'One of the top resource-intensive queries may be dramatically improved by adding an index.' ) AS Details ,
10714 qs.query_plan ,
10715 qs.query_plan_filtered
10716 FROM #dm_exec_query_stats qs
10717 WHERE COALESCE(qs.query_plan_filtered,
10718 CAST(qs.query_plan AS NVARCHAR(MAX))) LIKE '%MissingIndexGroup%'
10719 END
10720
10721 /* Look for cursors */
10722 IF NOT EXISTS ( SELECT 1
10723 FROM #SkipChecks
10724 WHERE DatabaseName IS NULL AND CheckID = 66 )
10725 BEGIN
10726 INSERT INTO #BlitzResults
10727 ( CheckID ,
10728 Priority ,
10729 FindingsGroup ,
10730 Finding ,
10731 URL ,
10732 Details ,
10733 QueryPlan ,
10734 QueryPlanFiltered
10735 )
10736 SELECT 66 AS CheckID ,
10737 120 AS Priority ,
10738 'Query Plans' AS FindingsGroup ,
10739 'Cursor' AS Finding ,
10740 'http://BrentOzar.com/go/cursor' AS URL ,
10741 ( 'One of the top resource-intensive queries is using a cursor.' ) AS Details ,
10742 qs.query_plan ,
10743 qs.query_plan_filtered
10744 FROM #dm_exec_query_stats qs
10745 WHERE COALESCE(qs.query_plan_filtered,
10746 CAST(qs.query_plan AS NVARCHAR(MAX))) LIKE '%<StmtCursor%'
10747 END
10748
10749 /* Look for scalar user-defined functions */
10750
10751 IF NOT EXISTS ( SELECT 1
10752 FROM #SkipChecks
10753 WHERE DatabaseName IS NULL AND CheckID = 67 )
10754 BEGIN
10755 INSERT INTO #BlitzResults
10756 ( CheckID ,
10757 Priority ,
10758 FindingsGroup ,
10759 Finding ,
10760 URL ,
10761 Details ,
10762 QueryPlan ,
10763 QueryPlanFiltered
10764 )
10765 SELECT 67 AS CheckID ,
10766 120 AS Priority ,
10767 'Query Plans' AS FindingsGroup ,
10768 'Scalar UDFs' AS Finding ,
10769 'http://BrentOzar.com/go/functions' AS URL ,
10770 ( 'One of the top resource-intensive queries is using a user-defined scalar function that may inhibit parallelism.' ) AS Details ,
10771 qs.query_plan ,
10772 qs.query_plan_filtered
10773 FROM #dm_exec_query_stats qs
10774 WHERE COALESCE(qs.query_plan_filtered,
10775 CAST(qs.query_plan AS NVARCHAR(MAX))) LIKE '%<UserDefinedFunction%'
10776 END
10777
10778 END /* IF @CheckProcedureCache = 1 */
10779
10780 /*Check for the last good DBCC CHECKDB date */
10781 IF NOT EXISTS ( SELECT 1
10782 FROM #SkipChecks
10783 WHERE DatabaseName IS NULL AND CheckID = 68 )
10784 BEGIN
10785 EXEC sp_MSforeachdb N'USE [?];
10786 INSERT #DBCCs
10787 (ParentObject,
10788 Object,
10789 Field,
10790 Value)
10791 EXEC (''DBCC DBInfo() With TableResults, NO_INFOMSGS'');
10792 UPDATE #DBCCs SET DbName = N''?'' WHERE DbName IS NULL;';
10793
10794 WITH DB2
10795 AS ( SELECT DISTINCT
10796 Field ,
10797 Value ,
10798 DbName
10799 FROM #DBCCs
10800 WHERE Field = 'dbi_dbccLastKnownGood'
10801 )
10802 INSERT INTO #BlitzResults
10803 ( CheckID ,
10804 DatabaseName ,
10805 Priority ,
10806 FindingsGroup ,
10807 Finding ,
10808 URL ,
10809 Details
10810 )
10811 SELECT 68 AS CheckID ,
10812 DB2.DbName AS DatabaseName ,
10813 50 AS PRIORITY ,
10814 'Reliability' AS FindingsGroup ,
10815 'Last good DBCC CHECKDB over 2 weeks old' AS Finding ,
10816 'http://BrentOzar.com/go/checkdb' AS URL ,
10817 'Database [' + DB2.DbName + ']'
10818 + CASE DB2.Value
10819 WHEN '1900-01-01 00:00:00.000'
10820 THEN ' never had a successful DBCC CHECKDB.'
10821 ELSE ' last had a successful DBCC CHECKDB run on '
10822 + DB2.Value + '.'
10823 END
10824 + ' This check should be run regularly to catch any database corruption as soon as possible.'
10825 + ' Note: you can restore a backup of a busy production database to a test server and run DBCC CHECKDB '
10826 + ' against that to minimize impact. If you do that, you can ignore this warning.' AS Details
10827 FROM DB2
10828 WHERE DB2.DbName NOT IN ( SELECT DISTINCT
10829 DatabaseName
10830 FROM
10831 #SkipChecks )
10832 AND CONVERT(DATETIME, DB2.Value, 121) < DATEADD(DD,
10833 -14,
10834 CURRENT_TIMESTAMP)
10835 END
10836
10837 /*Check for high VLF count: this will omit any database snapshots*/
10838
10839 IF NOT EXISTS ( SELECT 1
10840 FROM #SkipChecks
10841 WHERE DatabaseName IS NULL AND CheckID = 69 )
10842 BEGIN
10843 IF @@VERSION LIKE 'Microsoft SQL Server 2012%' OR @@VERSION LIKE 'Microsoft SQL Server 2014%'
10844 BEGIN
10845 EXEC sp_MSforeachdb N'USE [?];
10846 INSERT INTO #LogInfo2012
10847 EXEC sp_executesql N''DBCC LogInfo() WITH NO_INFOMSGS'';
10848 IF @@ROWCOUNT > 999
10849 BEGIN
10850 INSERT INTO #BlitzResults
10851 ( CheckID
10852 ,DatabaseName
10853 ,Priority
10854 ,FindingsGroup
10855 ,Finding
10856 ,URL
10857 ,Details)
10858 SELECT 69
10859 ,DB_NAME()
10860 ,100
10861 ,''Performance''
10862 ,''High VLF Count''
10863 ,''http://BrentOzar.com/go/vlf''
10864 ,''The ['' + DB_NAME() + ''] database has '' + CAST(COUNT(*) as VARCHAR(20)) + '' virtual log files (VLFs). This may be slowing down startup, restores, and even inserts/updates/deletes.''
10865 FROM #LogInfo2012
10866 WHERE EXISTS (SELECT name FROM master.sys.databases
10867 WHERE source_database_id is null) ;
10868 END
10869 TRUNCATE TABLE #LogInfo2012;'
10870 DROP TABLE #LogInfo2012;
10871 END
10872 ELSE
10873 BEGIN
10874 EXEC sp_MSforeachdb N'USE [?];
10875 INSERT INTO #LogInfo
10876 EXEC sp_executesql N''DBCC LogInfo() WITH NO_INFOMSGS'';
10877 IF @@ROWCOUNT > 999
10878 BEGIN
10879 INSERT INTO #BlitzResults
10880 ( CheckID
10881 ,DatabaseName
10882 ,Priority
10883 ,FindingsGroup
10884 ,Finding
10885 ,URL
10886 ,Details)
10887 SELECT 69
10888 ,DB_NAME()
10889 ,100
10890 ,''Performance''
10891 ,''High VLF Count''
10892 ,''http://BrentOzar.com/go/vlf''
10893 ,''The ['' + DB_NAME() + ''] database has '' + CAST(COUNT(*) as VARCHAR(20)) + '' virtual log files (VLFs). This may be slowing down startup, restores, and even inserts/updates/deletes.''
10894 FROM #LogInfo
10895 WHERE EXISTS (SELECT name FROM master.sys.databases
10896 WHERE source_database_id is null);
10897 END
10898 TRUNCATE TABLE #LogInfo;'
10899 DROP TABLE #LogInfo;
10900 END
10901 END
10902 /*Verify that the servername is set */
10903 /*Verify that the servername is set */
10904 IF NOT EXISTS ( SELECT 1
10905 FROM #SkipChecks
10906 WHERE DatabaseName IS NULL AND CheckID = 70 )
10907 BEGIN
10908 IF @@SERVERNAME IS NULL
10909 BEGIN
10910 INSERT INTO #BlitzResults
10911 ( CheckID ,
10912 Priority ,
10913 FindingsGroup ,
10914 Finding ,
10915 URL ,
10916 Details
10917 )
10918 SELECT 70 AS CheckID ,
10919 200 AS Priority ,
10920 'Configuration' AS FindingsGroup ,
10921 '@@Servername Not Set' AS Finding ,
10922 'http://BrentOzar.com/go/servername' AS URL ,
10923 '@@Servername variable is null. You can fix it by executing: "sp_addserver ''<LocalServerName>'', local"' AS Details
10924 END;
10925
10926 IF /* @@SERVERNAME IS set */
10927 (@@SERVERNAME IS NOT NULL
10928 AND
10929 /* not a named instance */
10930 CHARINDEX('\',CAST(SERVERPROPERTY('ServerName') AS NVARCHAR)) = 0
10931 AND
10932 /* not clustered, when computername may be different than the servername */
10933 SERVERPROPERTY('IsClustered') = 0
10934 AND
10935 /* @@SERVERNAME is different than the computer name */
10936 @@SERVERNAME <> CAST(ISNULL(SERVERPROPERTY('ComputerNamePhysicalNetBIOS'),@@SERVERNAME) AS NVARCHAR) )
10937 BEGIN
10938 INSERT INTO #BlitzResults
10939 ( CheckID ,
10940 Priority ,
10941 FindingsGroup ,
10942 Finding ,
10943 URL ,
10944 Details
10945 )
10946 SELECT 70 AS CheckID ,
10947 200 AS Priority ,
10948 'Configuration' AS FindingsGroup ,
10949 '@@Servername Not Correct' AS Finding ,
10950 'http://BrentOzar.com/go/servername' AS URL ,
10951 'The @@Servername is different than the computer name, which may trigger certificate errors.' AS Details
10952 END;
10953
10954 END
10955 /*Check to see if a failsafe operator has been configured*/
10956 IF NOT EXISTS ( SELECT 1
10957 FROM #SkipChecks
10958 WHERE DatabaseName IS NULL AND CheckID = 73 )
10959 BEGIN
10960
10961 DECLARE @AlertInfo TABLE
10962 (
10963 FailSafeOperator NVARCHAR(255) ,
10964 NotificationMethod INT ,
10965 ForwardingServer NVARCHAR(255) ,
10966 ForwardingSeverity INT ,
10967 PagerToTemplate NVARCHAR(255) ,
10968 PagerCCTemplate NVARCHAR(255) ,
10969 PagerSubjectTemplate NVARCHAR(255) ,
10970 PagerSendSubjectOnly NVARCHAR(255) ,
10971 ForwardAlways INT
10972 )
10973 INSERT INTO @AlertInfo
10974 EXEC [master].[dbo].[sp_MSgetalertinfo] @includeaddresses = 0
10975 INSERT INTO #BlitzResults
10976 ( CheckID ,
10977 Priority ,
10978 FindingsGroup ,
10979 Finding ,
10980 URL ,
10981 Details
10982 )
10983 SELECT 73 AS CheckID ,
10984 50 AS Priority ,
10985 'Reliability' AS FindingsGroup ,
10986 'No failsafe operator configured' AS Finding ,
10987 'http://BrentOzar.com/go/failsafe' AS URL ,
10988 ( 'No failsafe operator is configured on this server. This is a good idea just in-case there are issues with the [msdb] database that prevents alerting.' ) AS Details
10989 FROM @AlertInfo
10990 WHERE FailSafeOperator IS NULL;
10991 END
10992
10993 /*Identify globally enabled trace flags*/
10994 IF NOT EXISTS ( SELECT 1
10995 FROM #SkipChecks
10996 WHERE DatabaseName IS NULL AND CheckID = 74 )
10997 BEGIN
10998 INSERT INTO #TraceStatus
10999 EXEC ( ' DBCC TRACESTATUS(-1) WITH NO_INFOMSGS'
11000 )
11001 INSERT INTO #BlitzResults
11002 ( CheckID ,
11003 Priority ,
11004 FindingsGroup ,
11005 Finding ,
11006 URL ,
11007 Details
11008 )
11009 SELECT 74 AS CheckID ,
11010 200 AS Priority ,
11011 'Global Trace Flag' AS FindingsGroup ,
11012 'TraceFlag On' AS Finding ,
11013 'http://www.BrentOzar.com/go/traceflags/' AS URL ,
11014 'Trace flag ' + T.TraceFlag
11015 + ' is enabled globally.' AS Details
11016 FROM #TraceStatus T
11017 END
11018
11019 /*Check for transaction log file larger than data file */
11020 IF NOT EXISTS ( SELECT 1
11021 FROM #SkipChecks
11022 WHERE DatabaseName IS NULL AND CheckID = 75 )
11023 BEGIN
11024 INSERT INTO #BlitzResults
11025 ( CheckID ,
11026 DatabaseName ,
11027 Priority ,
11028 FindingsGroup ,
11029 Finding ,
11030 URL ,
11031 Details
11032 )
11033 SELECT 75 AS CheckID ,
11034 DB_NAME(a.database_id) ,
11035 50 AS Priority ,
11036 'Reliability' AS FindingsGroup ,
11037 'Transaction Log Larger than Data File' AS Finding ,
11038 'http://BrentOzar.com/go/biglog' AS URL ,
11039 'The database [' + DB_NAME(a.database_id)
11040 + '] has a transaction log file larger than a data file. This may indicate that transaction log backups are not being performed or not performed often enough.' AS Details
11041 FROM sys.master_files a
11042 WHERE a.type = 1
11043 AND DB_NAME(a.database_id) NOT IN (
11044 SELECT DISTINCT
11045 DatabaseName
11046 FROM #SkipChecks )
11047 AND a.size > 125000 /* Size is measured in pages here, so this gets us log files over 1GB. */
11048 AND a.size > ( SELECT SUM(CAST(b.size AS BIGINT))
11049 FROM sys.master_files b
11050 WHERE a.database_id = b.database_id
11051 AND b.type = 0
11052 )
11053 AND a.database_id IN (
11054 SELECT database_id
11055 FROM sys.databases
11056 WHERE source_database_id IS NULL )
11057 END
11058
11059 /*Check for collation conflicts between user databases and tempdb */
11060 IF NOT EXISTS ( SELECT 1
11061 FROM #SkipChecks
11062 WHERE DatabaseName IS NULL AND CheckID = 76 )
11063 BEGIN
11064 INSERT INTO #BlitzResults
11065 ( CheckID ,
11066 DatabaseName ,
11067 Priority ,
11068 FindingsGroup ,
11069 Finding ,
11070 URL ,
11071 Details
11072 )
11073 SELECT 76 AS CheckID ,
11074 name AS DatabaseName ,
11075 50 AS Priority ,
11076 'Reliability' AS FindingsGroup ,
11077 'Collation for ' + name
11078 + ' different than tempdb collation' AS Finding ,
11079 'http://BrentOzar.com/go/collate' AS URL ,
11080 'Collation differences between user databases and tempdb can cause conflicts especially when comparing string values' AS Details
11081 FROM sys.databases
11082 WHERE name NOT IN ( 'master', 'model', 'msdb')
11083 AND name NOT LIKE 'ReportServer%'
11084 AND name NOT IN ( SELECT DISTINCT
11085 DatabaseName
11086 FROM #SkipChecks )
11087 AND collation_name <> ( SELECT
11088 collation_name
11089 FROM
11090 sys.databases
11091 WHERE
11092 name = 'tempdb'
11093 )
11094 END
11095
11096 IF NOT EXISTS ( SELECT 1
11097 FROM #SkipChecks
11098 WHERE DatabaseName IS NULL AND CheckID = 77 )
11099 BEGIN
11100 INSERT INTO #BlitzResults
11101 ( CheckID ,
11102 DatabaseName ,
11103 Priority ,
11104 FindingsGroup ,
11105 Finding ,
11106 URL ,
11107 Details
11108 )
11109 SELECT 77 AS CheckID ,
11110 dSnap.[name] AS DatabaseName ,
11111 50 AS Priority ,
11112 'Reliability' AS FindingsGroup ,
11113 'Database Snapshot Online' AS Finding ,
11114 'http://BrentOzar.com/go/snapshot' AS URL ,
11115 'Database [' + dSnap.[name]
11116 + '] is a snapshot of ['
11117 + dOriginal.[name]
11118 + ']. Make sure you have enough drive space to maintain the snapshot as the original database grows.' AS Details
11119 FROM sys.databases dSnap
11120 INNER JOIN sys.databases dOriginal ON dSnap.source_database_id = dOriginal.database_id
11121 AND dSnap.name NOT IN (
11122 SELECT DISTINCT
11123 DatabaseName
11124 FROM
11125 #SkipChecks )
11126 END
11127
11128 IF NOT EXISTS ( SELECT 1
11129 FROM #SkipChecks
11130 WHERE DatabaseName IS NULL AND CheckID = 79 )
11131 BEGIN
11132 INSERT INTO #BlitzResults
11133 ( CheckID ,
11134 Priority ,
11135 FindingsGroup ,
11136 Finding ,
11137 URL ,
11138 Details
11139 )
11140 SELECT 79 AS CheckID ,
11141 100 AS Priority ,
11142 'Performance' AS FindingsGroup ,
11143 'Shrink Database Job' AS Finding ,
11144 'http://BrentOzar.com/go/autoshrink' AS URL ,
11145 'In the [' + j.[name] + '] job, step ['
11146 + step.[step_name]
11147 + '] has SHRINKDATABASE or SHRINKFILE, which may be causing database fragmentation.' AS Details
11148 FROM msdb.dbo.sysjobs j
11149 INNER JOIN msdb.dbo.sysjobsteps step ON j.job_id = step.job_id
11150 WHERE step.command LIKE N'%SHRINKDATABASE%'
11151 OR step.command LIKE N'%SHRINKFILE%'
11152 END
11153
11154 IF NOT EXISTS ( SELECT 1
11155 FROM #SkipChecks
11156 WHERE DatabaseName IS NULL AND CheckID = 80 )
11157 BEGIN
11158 EXEC dbo.sp_MSforeachdb 'USE [?]; INSERT INTO #BlitzResults (CheckID, DatabaseName, Priority, FindingsGroup, Finding, URL, Details) SELECT DISTINCT 80, DB_NAME(), 50, ''Reliability'', ''Max File Size Set'', ''http://BrentOzar.com/go/maxsize'', (''The ['' + DB_NAME() + ''] database file '' + name + '' has a max file size set to '' + CAST(CAST(max_size AS BIGINT) * 8 / 1024 AS VARCHAR(100)) + ''MB. If it runs out of space, the database will stop working even though there may be drive space available.'') FROM sys.database_files WHERE max_size <> 268435456 AND max_size <> -1 AND type <> 2';
11159 END
11160
11161 IF NOT EXISTS ( SELECT 1
11162 FROM #SkipChecks
11163 WHERE DatabaseName IS NULL AND CheckID = 81 )
11164 BEGIN
11165 INSERT INTO #BlitzResults
11166 ( CheckID ,
11167 Priority ,
11168 FindingsGroup ,
11169 Finding ,
11170 URL ,
11171 Details
11172 )
11173 SELECT 81 AS CheckID ,
11174 200 AS Priority ,
11175 'Non-Active Server Config' AS FindingsGroup ,
11176 cr.name AS Finding ,
11177 'http://www.BrentOzar.com/blitz/sp_configure/' AS URL ,
11178 ( 'This sp_configure option isn''t running under its set value. Its set value is '
11179 + CAST(cr.[Value] AS VARCHAR(100))
11180 + ' and its running value is '
11181 + CAST(cr.value_in_use AS VARCHAR(100))
11182 + '. When someone does a RECONFIGURE or restarts the instance, this setting will start taking effect.' ) AS Details
11183 FROM sys.configurations cr
11184 WHERE cr.value <> cr.value_in_use;
11185 END
11186
11187 IF NOT EXISTS ( SELECT 1
11188 FROM #SkipChecks
11189 WHERE DatabaseName IS NULL AND CheckID = 123 )
11190 BEGIN
11191 INSERT INTO #BlitzResults
11192 ( CheckID ,
11193 Priority ,
11194 FindingsGroup ,
11195 Finding ,
11196 URL ,
11197 Details
11198 )
11199 SELECT TOP 1 123 AS CheckID ,
11200 200 AS Priority ,
11201 'Performance' AS FindingsGroup ,
11202 'Agent Jobs Starting Simultaneously' AS Finding ,
11203 'http://BrentOzar.com/go/busyagent/' AS URL ,
11204 ( 'Multiple SQL Server Agent jobs are configured to start simultaneously. For detailed schedule listings, see the query in the URL.' ) AS Details
11205 FROM msdb.dbo.sysjobactivity
11206 WHERE start_execution_date > DATEADD(dd, -14, GETDATE())
11207 GROUP BY start_execution_date HAVING COUNT(*) > 1;
11208 END
11209
11210
11211 IF @CheckServerInfo = 1
11212 BEGIN
11213
11214 IF NOT EXISTS ( SELECT 1
11215 FROM #SkipChecks
11216 WHERE DatabaseName IS NULL AND CheckID = 83 )
11217 BEGIN
11218 IF EXISTS ( SELECT *
11219 FROM sys.all_objects
11220 WHERE name = 'dm_server_services' )
11221 BEGIN
11222 SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
11223 SELECT 83 AS CheckID ,
11224 250 AS Priority ,
11225 ''Server Info'' AS FindingsGroup ,
11226 ''Services'' AS Finding ,
11227 '''' AS URL ,
11228 N''Service: '' + servicename + N'' runs under service account '' + service_account + N''. Last startup time: '' + COALESCE(CAST(CAST(last_startup_time AS DATETIME) AS VARCHAR(50)), ''not shown.'') + ''. Startup type: '' + startup_type_desc + N'', currently '' + status_desc + ''.''
11229 FROM sys.dm_server_services;'
11230 EXECUTE(@StringToExecute);
11231 END
11232 END
11233
11234 /* Check 84 - SQL Server 2012 */
11235 IF NOT EXISTS ( SELECT 1
11236 FROM #SkipChecks
11237 WHERE DatabaseName IS NULL AND CheckID = 84 )
11238 BEGIN
11239 IF EXISTS ( SELECT *
11240 FROM sys.all_objects o
11241 INNER JOIN sys.all_columns c ON o.object_id = c.object_id
11242 WHERE o.name = 'dm_os_sys_info'
11243 AND c.name = 'physical_memory_kb' )
11244 BEGIN
11245 SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
11246 SELECT 84 AS CheckID ,
11247 250 AS Priority ,
11248 ''Server Info'' AS FindingsGroup ,
11249 ''Hardware'' AS Finding ,
11250 '''' AS URL ,
11251 ''Logical processors: '' + CAST(cpu_count AS VARCHAR(50)) + ''. Physical memory: '' + CAST( CAST(ROUND((physical_memory_kb / 1024.0 / 1024), 1) AS INT) AS VARCHAR(50)) + ''GB.''
11252 FROM sys.dm_os_sys_info';
11253 EXECUTE(@StringToExecute);
11254 END
11255
11256 /* Check 84 - SQL Server 2008 */
11257 IF EXISTS ( SELECT *
11258 FROM sys.all_objects o
11259 INNER JOIN sys.all_columns c ON o.object_id = c.object_id
11260 WHERE o.name = 'dm_os_sys_info'
11261 AND c.name = 'physical_memory_in_bytes' )
11262 BEGIN
11263 SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
11264 SELECT 84 AS CheckID ,
11265 250 AS Priority ,
11266 ''Server Info'' AS FindingsGroup ,
11267 ''Hardware'' AS Finding ,
11268 '''' AS URL ,
11269 ''Logical processors: '' + CAST(cpu_count AS VARCHAR(50)) + ''. Physical memory: '' + CAST( CAST(ROUND((physical_memory_in_bytes / 1024.0 / 1024 / 1024), 1) AS INT) AS VARCHAR(50)) + ''GB.''
11270 FROM sys.dm_os_sys_info';
11271 EXECUTE(@StringToExecute);
11272 END
11273 END
11274
11275
11276 IF NOT EXISTS ( SELECT 1
11277 FROM #SkipChecks
11278 WHERE DatabaseName IS NULL AND CheckID = 85 )
11279 BEGIN
11280 INSERT INTO #BlitzResults
11281 ( CheckID ,
11282 Priority ,
11283 FindingsGroup ,
11284 Finding ,
11285 URL ,
11286 Details
11287 )
11288 SELECT 85 AS CheckID ,
11289 250 AS Priority ,
11290 'Server Info' AS FindingsGroup ,
11291 'SQL Server Service' AS Finding ,
11292 '' AS URL ,
11293 N'Version: '
11294 + CAST(SERVERPROPERTY('productversion') AS NVARCHAR(100))
11295 + N'. Patch Level: '
11296 + CAST(SERVERPROPERTY('productlevel') AS NVARCHAR(100))
11297 + N'. Edition: '
11298 + CAST(SERVERPROPERTY('edition') AS VARCHAR(100))
11299 + N'. AlwaysOn Enabled: '
11300 + CAST(COALESCE(SERVERPROPERTY('IsHadrEnabled'),
11301 0) AS VARCHAR(100))
11302 + N'. AlwaysOn Mgr Status: '
11303 + CAST(COALESCE(SERVERPROPERTY('HadrManagerStatus'),
11304 0) AS VARCHAR(100))
11305 END
11306
11307
11308 IF NOT EXISTS ( SELECT 1
11309 FROM #SkipChecks
11310 WHERE DatabaseName IS NULL AND CheckID = 88 )
11311 BEGIN
11312 INSERT INTO #BlitzResults
11313 ( CheckID ,
11314 Priority ,
11315 FindingsGroup ,
11316 Finding ,
11317 URL ,
11318 Details
11319 )
11320 SELECT 88 AS CheckID ,
11321 250 AS Priority ,
11322 'Server Info' AS FindingsGroup ,
11323 'SQL Server Last Restart' AS Finding ,
11324 '' AS URL ,
11325 CAST(create_date AS VARCHAR(100))
11326 FROM sys.databases
11327 WHERE database_id = 2
11328 END
11329
11330 IF NOT EXISTS ( SELECT 1
11331 FROM #SkipChecks
11332 WHERE DatabaseName IS NULL AND CheckID = 92 )
11333 BEGIN
11334 INSERT INTO #driveInfo
11335 ( drive, SIZE )
11336 EXEC master..xp_fixeddrives
11337
11338 INSERT INTO #BlitzResults
11339 ( CheckID ,
11340 Priority ,
11341 FindingsGroup ,
11342 Finding ,
11343 URL ,
11344 Details
11345 )
11346 SELECT 92 AS CheckID ,
11347 250 AS Priority ,
11348 'Server Info' AS FindingsGroup ,
11349 'Drive ' + i.drive + ' Space' AS Finding ,
11350 '' AS URL ,
11351 CAST(i.SIZE AS VARCHAR)
11352 + 'MB free on ' + i.drive
11353 + ' drive' AS Details
11354 FROM #driveInfo AS i
11355 DROP TABLE #driveInfo
11356 END
11357
11358
11359 IF NOT EXISTS ( SELECT 1
11360 FROM #SkipChecks
11361 WHERE DatabaseName IS NULL AND CheckID = 103 )
11362 AND EXISTS ( SELECT *
11363 FROM sys.all_objects o
11364 INNER JOIN sys.all_columns c ON o.object_id = c.object_id
11365 WHERE o.name = 'dm_os_sys_info'
11366 AND c.name = 'virtual_machine_type_desc' )
11367 BEGIN
11368 SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
11369 SELECT 103 AS CheckID,
11370 250 AS Priority,
11371 ''Server Info'' AS FindingsGroup,
11372 ''Virtual Server'' AS Finding,
11373 ''http://BrentOzar.com/go/virtual'' AS URL,
11374 ''Type: ('' + virtual_machine_type_desc + '')'' AS Details
11375 FROM sys.dm_os_sys_info
11376 WHERE virtual_machine_type <> 0';
11377 EXECUTE(@StringToExecute);
11378 END
11379
11380 IF NOT EXISTS ( SELECT 1
11381 FROM #SkipChecks
11382 WHERE DatabaseName IS NULL AND CheckID = 114 )
11383 AND EXISTS ( SELECT *
11384 FROM sys.all_objects o
11385 WHERE o.name = 'dm_os_memory_nodes' )
11386 AND EXISTS ( SELECT *
11387 FROM sys.all_objects o
11388 INNER JOIN sys.all_columns c ON o.object_id = c.object_id
11389 WHERE o.name = 'dm_os_nodes'
11390 AND c.name = 'processor_group' )
11391 BEGIN
11392 SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
11393 SELECT 114 AS CheckID ,
11394 250 AS Priority ,
11395 ''Server Info'' AS FindingsGroup ,
11396 ''Hardware - NUMA Config'' AS Finding ,
11397 '''' AS URL ,
11398 ''Node: '' + CAST(n.node_id AS NVARCHAR(10)) + '' State: '' + node_state_desc
11399 + '' Online schedulers: '' + CAST(n.online_scheduler_count AS NVARCHAR(10)) + '' Processor Group: '' + CAST(n.processor_group AS NVARCHAR(10))
11400 + '' Memory node: '' + CAST(n.memory_node_id AS NVARCHAR(10)) + '' Memory VAS Reserved GB: '' + CAST(CAST((m.virtual_address_space_reserved_kb / 1024.0 / 1024) AS INT) AS NVARCHAR(100))
11401 FROM sys.dm_os_nodes n
11402 INNER JOIN sys.dm_os_memory_nodes m ON n.memory_node_id = m.memory_node_id
11403 WHERE n.node_state_desc NOT LIKE ''%DAC%''
11404 ORDER BY n.node_id'
11405 EXECUTE(@StringToExecute);
11406 END
11407
11408
11409 IF NOT EXISTS ( SELECT 1
11410 FROM #SkipChecks
11411 WHERE DatabaseName IS NULL AND CheckID = 106 )
11412 AND (select convert(int,value_in_use) from sys.configurations where name = 'default trace enabled' ) = 1
11413 BEGIN
11414
11415 INSERT INTO #BlitzResults
11416 ( CheckID ,
11417 Priority ,
11418 FindingsGroup ,
11419 Finding ,
11420 URL ,
11421 Details
11422 )
11423 SELECT
11424 106 AS CheckID
11425 ,250 AS Priority
11426 ,'Server Info' AS FindingsGroup
11427 ,'Default Trace Contents' AS Finding
11428 ,'http://BrentOzar.com/go/trace' AS URL
11429 ,'The default trace holds '+cast(DATEDIFF(hour,MIN(StartTime),GETDATE())as varchar)+' hours of data'
11430 +' between '+cast(Min(StartTime) as varchar)+' and '+cast(GETDATE()as varchar)
11431 +('. The default trace files are located in: '+left( @curr_tracefilename,len(@curr_tracefilename) - @indx)
11432 ) as Details
11433 FROM ::fn_trace_gettable( @base_tracefilename, default )
11434 WHERE EventClass BETWEEN 65500 and 65600
11435 END /* CheckID 106 */
11436
11437
11438
11439 END /* IF @CheckServerInfo = 1 */
11440 END /* IF ( ( SERVERPROPERTY('ServerName') NOT IN ( SELECT ServerName */
11441
11442
11443 /* Delete priorites they wanted to skip. */
11444 IF @IgnorePrioritiesAbove IS NOT NULL
11445 DELETE #BlitzResults
11446 WHERE [Priority] > @IgnorePrioritiesAbove AND CheckID <> -1;
11447
11448 IF @IgnorePrioritiesBelow IS NOT NULL
11449 DELETE #BlitzResults
11450 WHERE [Priority] < @IgnorePrioritiesBelow AND CheckID <> -1;
11451
11452 /* Delete checks they wanted to skip. */
11453 IF @SkipChecksTable IS NOT NULL
11454 BEGIN
11455 DELETE FROM #BlitzResults
11456 WHERE DatabaseName IN ( SELECT DatabaseName
11457 FROM #SkipChecks
11458 WHERE CheckID IS NULL
11459 AND (ServerName IS NULL OR ServerName = SERVERPROPERTY('ServerName')));
11460 DELETE FROM #BlitzResults
11461 WHERE CheckID IN ( SELECT CheckID
11462 FROM #SkipChecks
11463 WHERE DatabaseName IS NULL
11464 AND (ServerName IS NULL OR ServerName = SERVERPROPERTY('ServerName')));
11465 DELETE r FROM #BlitzResults r
11466 INNER JOIN #SkipChecks c ON r.DatabaseName = c.DatabaseName and r.CheckID = c.CheckID
11467 AND (ServerName IS NULL OR ServerName = SERVERPROPERTY('ServerName'));
11468 END
11469
11470 /* Add summary mode */
11471 IF @SummaryMode > 0
11472 BEGIN
11473 UPDATE #BlitzResults
11474 SET Finding = br.Finding + ' (' + CAST(brTotals.recs AS NVARCHAR(20)) + ')'
11475 FROM #BlitzResults br
11476 INNER JOIN (SELECT FindingsGroup, Finding, Priority, COUNT(*) AS recs FROM #BlitzResults GROUP BY FindingsGroup, Finding, Priority) brTotals ON br.FindingsGroup = brTotals.FindingsGroup AND br.Finding = brTotals.Finding AND br.Priority = brTotals.Priority
11477 WHERE brTotals.recs > 1;
11478
11479 DELETE br
11480 FROM #BlitzResults br
11481 WHERE EXISTS (SELECT * FROM #BlitzResults brLower WHERE br.FindingsGroup = brLower.FindingsGroup AND br.Finding = brLower.Finding AND br.Priority = brLower.Priority AND br.ID > brLower.ID);
11482
11483 END
11484
11485 /* Add credits for the nice folks who put so much time into building and maintaining this for free: */
11486 INSERT INTO #BlitzResults
11487 ( CheckID ,
11488 Priority ,
11489 FindingsGroup ,
11490 Finding ,
11491 URL ,
11492 Details
11493 )
11494 VALUES ( -1 ,
11495 255 ,
11496 'Thanks!' ,
11497 'From Brent Ozar Unlimited' ,
11498 'http://www.BrentOzar.com/blitz/' ,
11499 'Thanks from the Brent Ozar Unlimited team. We hope you found this tool useful, and if you need help relieving your SQL Server pains, email us at Help@BrentOzar.com.'
11500 );
11501
11502 INSERT INTO #BlitzResults
11503 ( CheckID ,
11504 Priority ,
11505 FindingsGroup ,
11506 Finding ,
11507 URL ,
11508 Details
11509
11510 )
11511 VALUES ( -1 ,
11512 0 ,
11513 'sp_Blitz (TM) v' + CAST(@Version AS VARCHAR(20)) + ' as of ' + CAST(CONVERT(DATETIME, @VersionDate, 102) AS VARCHAR(100)),
11514 'From Brent Ozar Unlimited' ,
11515 'http://www.BrentOzar.com/blitz/' ,
11516 'Thanks from the Brent Ozar Unlimited team. We hope you found this tool useful, and if you need help relieving your SQL Server pains, email us at Help@BrentOzar.com.'
11517
11518 );
11519
11520 IF @EmailRecipients IS NOT NULL
11521 BEGIN
11522 /* Database mail won't work off a local temp table. I'm not happy about this hacky workaround either. */
11523 IF (OBJECT_ID('tempdb..##BlitzResults', 'U') IS NOT NULL) DROP TABLE ##BlitzResults;
11524 SELECT * INTO ##BlitzResults FROM #BlitzResults;
11525 SET @query_result_separator = char(9);
11526 SET @StringToExecute = 'SET NOCOUNT ON;SELECT [Priority] , [FindingsGroup] , [Finding] , [DatabaseName] , [URL] , [Details] , CheckID FROM ##BlitzResults ORDER BY Priority , FindingsGroup, Finding, Details; SET NOCOUNT OFF;';
11527 SET @EmailSubject = 'sp_Blitz (TM) Results for ' + @@SERVERNAME;
11528 SET @EmailBody = 'sp_Blitz (TM) v' + CAST(@Version AS VARCHAR(20)) + ' as of ' + CAST(CONVERT(DATETIME, @VersionDate, 102) AS VARCHAR(100)) + '. From Brent Ozar Unlimited: http://www.BrentOzar.com/blitz/';
11529 IF @EmailProfile IS NULL
11530 EXEC msdb.dbo.sp_send_dbmail
11531 @recipients = @EmailRecipients,
11532 @subject = @EmailSubject,
11533 @body = @EmailBody,
11534 @query_attachment_filename = 'sp_Blitz-Results.csv',
11535 @attach_query_result_as_file = 1,
11536 @query_result_header = 1,
11537 @query_result_width = 32767,
11538 @append_query_error = 1,
11539 @query_result_no_padding = 1,
11540 @query_result_separator = @query_result_separator,
11541 @query = @StringToExecute;
11542 ELSE
11543 EXEC msdb.dbo.sp_send_dbmail
11544 @profile_name = @EmailProfile,
11545 @recipients = @EmailRecipients,
11546 @subject = @EmailSubject,
11547 @body = @EmailBody,
11548 @query_attachment_filename = 'sp_Blitz-Results.csv',
11549 @attach_query_result_as_file = 1,
11550 @query_result_header = 1,
11551 @query_result_width = 32767,
11552 @append_query_error = 1,
11553 @query_result_no_padding = 1,
11554 @query_result_separator = @query_result_separator,
11555 @query = @StringToExecute;
11556 IF (OBJECT_ID('tempdb..##BlitzResults', 'U') IS NOT NULL) DROP TABLE ##BlitzResults;
11557 END
11558
11559
11560 /* @OutputTableName lets us export the results to a permanent table */
11561 IF @OutputDatabaseName IS NOT NULL
11562 AND @OutputSchemaName IS NOT NULL
11563 AND @OutputTableName IS NOT NULL
11564 AND EXISTS ( SELECT *
11565 FROM sys.databases
11566 WHERE QUOTENAME([name]) = @OutputDatabaseName)
11567 BEGIN
11568 SET @StringToExecute = 'USE '
11569 + @OutputDatabaseName
11570 + '; IF EXISTS(SELECT * FROM '
11571 + @OutputDatabaseName
11572 + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
11573 + @OutputSchemaName
11574 + ''') AND NOT EXISTS (SELECT * FROM '
11575 + @OutputDatabaseName
11576 + '.INFORMATION_SCHEMA.TABLES WHERE QUOTENAME(TABLE_SCHEMA) = '''
11577 + @OutputSchemaName + ''' AND QUOTENAME(TABLE_NAME) = '''
11578 + @OutputTableName + ''') CREATE TABLE '
11579 + @OutputSchemaName + '.'
11580 + @OutputTableName
11581 + ' (ID INT IDENTITY(1,1) NOT NULL,
11582 ServerName NVARCHAR(128),
11583 CheckDate DATETIME,
11584 BlitzVersion INT,
11585 Priority TINYINT ,
11586 FindingsGroup VARCHAR(50) ,
11587 Finding VARCHAR(200) ,
11588 DatabaseName NVARCHAR(128),
11589 URL VARCHAR(200) ,
11590 Details NVARCHAR(4000) ,
11591 QueryPlan [XML] NULL ,
11592 QueryPlanFiltered [NVARCHAR](MAX) NULL,
11593 CheckID INT ,
11594 CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
11595 EXEC(@StringToExecute);
11596 SET @StringToExecute = N' IF EXISTS(SELECT * FROM '
11597 + @OutputDatabaseName
11598 + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
11599 + @OutputSchemaName + ''') INSERT '
11600 + @OutputDatabaseName + '.'
11601 + @OutputSchemaName + '.'
11602 + @OutputTableName
11603 + ' (ServerName, CheckDate, BlitzVersion, CheckID, DatabaseName, Priority, FindingsGroup, Finding, URL, Details, QueryPlan, QueryPlanFiltered) SELECT '''
11604 + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
11605 + ''', GETDATE(), ' + CAST(@Version AS NVARCHAR(128))
11606 + ', CheckID, DatabaseName, Priority, FindingsGroup, Finding, URL, Details, QueryPlan, QueryPlanFiltered FROM #BlitzResults ORDER BY Priority , FindingsGroup , Finding , Details';
11607 EXEC(@StringToExecute);
11608 END
11609 ELSE IF (SUBSTRING(@OutputTableName, 2, 2) = '##')
11610 BEGIN
11611 SET @StringToExecute = N' IF (OBJECT_ID(''tempdb..'
11612 + @OutputTableName
11613 + ''') IS NOT NULL) DROP TABLE ' + @OutputTableName + ';'
11614 + 'CREATE TABLE '
11615 + @OutputTableName
11616 + ' (ID INT IDENTITY(1,1) NOT NULL,
11617 ServerName NVARCHAR(128),
11618 CheckDate DATETIME,
11619 BlitzVersion INT,
11620 Priority TINYINT ,
11621 FindingsGroup VARCHAR(50) ,
11622 Finding VARCHAR(200) ,
11623 DatabaseName NVARCHAR(128),
11624 URL VARCHAR(200) ,
11625 Details NVARCHAR(4000) ,
11626 QueryPlan [XML] NULL ,
11627 QueryPlanFiltered [NVARCHAR](MAX) NULL,
11628 CheckID INT ,
11629 CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
11630 + ' INSERT '
11631 + @OutputTableName
11632 + ' (ServerName, CheckDate, BlitzVersion, CheckID, DatabaseName, Priority, FindingsGroup, Finding, URL, Details, QueryPlan, QueryPlanFiltered) SELECT '''
11633 + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
11634 + ''', GETDATE(), ' + CAST(@Version AS NVARCHAR(128))
11635 + ', CheckID, DatabaseName, Priority, FindingsGroup, Finding, URL, Details, QueryPlan, QueryPlanFiltered FROM #BlitzResults ORDER BY Priority , FindingsGroup , Finding , Details';
11636 EXEC(@StringToExecute);
11637 END
11638 ELSE IF (SUBSTRING(@OutputTableName, 2, 1) = '#')
11639 BEGIN
11640 RAISERROR('Due to the nature of Dymamic SQL, only global (i.e. double pound (##)) temp tables are supported for @OutputTableName', 16, 0)
11641 END
11642
11643
11644 DECLARE @separator AS VARCHAR(1);
11645 IF @OutputType = 'RSV'
11646 SET @separator = CHAR(31);
11647 ELSE
11648 SET @separator = ',';
11649
11650 IF @OutputType = 'COUNT'
11651 BEGIN
11652 SELECT COUNT(*) AS Warnings
11653 FROM #BlitzResults
11654 END
11655 ELSE
11656 IF @OutputType IN ( 'CSV', 'RSV' )
11657 BEGIN
11658
11659 SELECT Result = CAST([Priority] AS NVARCHAR(100))
11660 + @separator + CAST(CheckID AS NVARCHAR(100))
11661 + @separator + COALESCE([FindingsGroup],
11662 '(N/A)') + @separator
11663 + COALESCE([Finding], '(N/A)') + @separator
11664 + COALESCE(DatabaseName, '(N/A)') + @separator
11665 + COALESCE([URL], '(N/A)') + @separator
11666 + COALESCE([Details], '(N/A)')
11667 FROM #BlitzResults
11668 ORDER BY Priority ,
11669 FindingsGroup ,
11670 Finding ,
11671 Details;
11672 END
11673 ELSE IF @OutputXMLasNVARCHAR = 1
11674 BEGIN
11675 SELECT [Priority] ,
11676 [FindingsGroup] ,
11677 [Finding] ,
11678 [DatabaseName] ,
11679 [URL] ,
11680 [Details] ,
11681 CAST([QueryPlan] AS NVARCHAR(MAX)) AS QueryPlan,
11682 [QueryPlanFiltered] ,
11683 CheckID
11684 FROM #BlitzResults
11685 ORDER BY Priority ,
11686 FindingsGroup ,
11687 Finding ,
11688 Details;
11689 END
11690 ELSE
11691 BEGIN
11692 SELECT [Priority] ,
11693 [FindingsGroup] ,
11694 [Finding] ,
11695 [DatabaseName] ,
11696 [URL] ,
11697 [Details] ,
11698 [QueryPlan] ,
11699 [QueryPlanFiltered] ,
11700 CheckID
11701 FROM #BlitzResults
11702 ORDER BY Priority ,
11703 FindingsGroup ,
11704 Finding ,
11705 Details;
11706 END
11707
11708 DROP TABLE #BlitzResults;
11709
11710 IF @OutputProcedureCache = 1
11711 AND @CheckProcedureCache = 1
11712 SELECT TOP 20
11713 total_worker_time / execution_count AS AvgCPU ,
11714 total_worker_time AS TotalCPU ,
11715 CAST(ROUND(100.00 * total_worker_time
11716 / ( SELECT SUM(total_worker_time)
11717 FROM sys.dm_exec_query_stats
11718 ), 2) AS MONEY) AS PercentCPU ,
11719 total_elapsed_time / execution_count AS AvgDuration ,
11720 total_elapsed_time AS TotalDuration ,
11721 CAST(ROUND(100.00 * total_elapsed_time
11722 / ( SELECT SUM(total_elapsed_time)
11723 FROM sys.dm_exec_query_stats
11724 ), 2) AS MONEY) AS PercentDuration ,
11725 total_logical_reads / execution_count AS AvgReads ,
11726 total_logical_reads AS TotalReads ,
11727 CAST(ROUND(100.00 * total_logical_reads
11728 / ( SELECT SUM(total_logical_reads)
11729 FROM sys.dm_exec_query_stats
11730 ), 2) AS MONEY) AS PercentReads ,
11731 execution_count ,
11732 CAST(ROUND(100.00 * execution_count
11733 / ( SELECT SUM(execution_count)
11734 FROM sys.dm_exec_query_stats
11735 ), 2) AS MONEY) AS PercentExecutions ,
11736 CASE WHEN DATEDIFF(mi, creation_time,
11737 qs.last_execution_time) = 0 THEN 0
11738 ELSE CAST(( 1.00 * execution_count / DATEDIFF(mi,
11739 creation_time,
11740 qs.last_execution_time) ) AS MONEY)
11741 END AS executions_per_minute ,
11742 qs.creation_time AS plan_creation_time ,
11743 qs.last_execution_time ,
11744 text ,
11745 text_filtered ,
11746 query_plan ,
11747 query_plan_filtered ,
11748 sql_handle ,
11749 query_hash ,
11750 plan_handle ,
11751 query_plan_hash
11752 FROM #dm_exec_query_stats qs
11753 ORDER BY CASE UPPER(@CheckProcedureCacheFilter)
11754 WHEN 'CPU' THEN total_worker_time
11755 WHEN 'READS' THEN total_logical_reads
11756 WHEN 'EXECCOUNT' THEN execution_count
11757 WHEN 'DURATION' THEN total_elapsed_time
11758 ELSE total_worker_time
11759 END DESC
11760
11761 END /* ELSE -- IF @OutputType = 'SCHEMA' */
11762 SET NOCOUNT OFF;
11763GO
11764
11765/*
11766--Sample execution call with the most common parameters:
11767EXEC [master].[dbo].[sp_Blitz]
11768 @CheckUserDatabaseObjects = 1 ,
11769 @CheckProcedureCache = 0 ,
11770 @OutputType = 'TABLE' ,
11771 @OutputProcedureCache = 0 ,
11772 @CheckProcedureCacheFilter = NULL,
11773 @CheckServerInfo = 1
11774*/