paraffin

sp_askbrent

Feb 25th, 2016
332
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 124.78 KB | None | 0 0
  1. IF OBJECT_ID('dbo.sp_AskBrent') IS NULL
  2. EXEC ('CREATE PROCEDURE dbo.sp_AskBrent AS RETURN 0;')
  3. GO
  4.  
  5.  
  6. ALTER PROCEDURE [dbo].[sp_AskBrent]
  7. @Question NVARCHAR(MAX) = NULL ,
  8. @AsOf DATETIME = NULL ,
  9. @ExpertMode TINYINT = 0 ,
  10. @Seconds INT = 5 ,
  11. @OutputType VARCHAR(20) = 'TABLE' ,
  12. @OutputDatabaseName NVARCHAR(128) = NULL ,
  13. @OutputSchemaName NVARCHAR(256) = NULL ,
  14. @OutputTableName NVARCHAR(256) = NULL ,
  15. @OutputTableNameFileStats NVARCHAR(256) = NULL ,
  16. @OutputTableNamePerfmonStats NVARCHAR(256) = NULL ,
  17. @OutputTableNameWaitStats NVARCHAR(256) = NULL ,
  18. @OutputXMLasNVARCHAR TINYINT = 0 ,
  19. @FilterPlansByDatabase VARCHAR(MAX) = NULL ,
  20. @SkipChecksQueries TINYINT = 1 ,
  21. @FileLatencyThresholdMS INT = 100 ,
  22. @Version INT = NULL OUTPUT,
  23. @VersionDate DATETIME = NULL OUTPUT
  24. WITH EXECUTE AS CALLER, RECOMPILE
  25. AS
  26. BEGIN
  27. SET NOCOUNT ON;
  28. SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
  29.  
  30. /*
  31. sp_AskBrent (TM)
  32.  
  33. (C) 2016, Brent Ozar Unlimited.
  34. See http://www.BrentOzar.com/go/eula for the End User Licensing Agreement.
  35.  
  36. Sure, the server needs tuning - but why is it slow RIGHT NOW?
  37. sp_AskBrent performs quick checks for things like:
  38.  
  39. * Blocking queries that have been running a long time
  40. * Backups, restores, DBCCs
  41. * Recently cleared plan cache
  42. * Transactions that are rolling back
  43.  
  44. To learn more, visit http://www.BrentOzar.com/askbrent/ where you can download
  45. new versions for free, watch training videos on how it works, get more info on
  46. the findings, and more. To contribute code and see your name in the change
  47. log, email your improvements & checks to [email protected].
  48.  
  49. Known limitations of this version:
  50. - No support for SQL Server 2000 or compatibility mode 80.
  51. - If a temp table called #CustomPerfmonCounters exists for any other session,
  52. but not our session, this stored proc will fail with an error saying the
  53. temp table #CustomPerfmonCounters doesn't exist.
  54.  
  55. Unknown limitations of this version:
  56. - None. Like Zombo.com, the only limit is yourself.
  57.  
  58. Changes in v20 - January 1, 2016
  59. - Andy McAuley fixed a SQL Server 2005 compatibility bug.
  60. - Trevor Hawkins fixed a bug in the view creation for looking at historical
  61. table captures.
  62. - Bug fixes.
  63.  
  64. Changes in v19 - October 6, 2015
  65. - If @OutputTable* parameters are populated, we also create a set of views to
  66. query the output tables. The views have the same database/schema/name as the
  67. output tables, and add _Delta as a suffix. Seriously, you do not want to see
  68. how the dynamic SQL works: http://dba.stackexchange.com/questions/12127/
  69. - @OutputTable* was rounding times to minutes, which wasn't a problem before,
  70. but now that we're more closely examining the output and using it for
  71. trending, every second matters.
  72.  
  73. Changes in v18 - September 11, 2015
  74. - Bug fixes. No improvements, just bug fixes.
  75.  
  76. Changes in v17 - July 19, 2015
  77. - Improving Azure SQL Database compatibility. (I didn't say it was fully
  78. compatible yet, I'm just saying it's more compatible than it was.)
  79.  
  80. */
  81.  
  82.  
  83. SELECT @Version = 20, @VersionDate = '20160101'
  84.  
  85. DECLARE @StringToExecute NVARCHAR(4000),
  86. @ParmDefinitions NVARCHAR(4000),
  87. @Parm1 NVARCHAR(4000),
  88. @OurSessionID INT,
  89. @LineFeed NVARCHAR(10),
  90. @StockWarningHeader NVARCHAR(500),
  91. @StockWarningFooter NVARCHAR(100),
  92. @StockDetailsHeader NVARCHAR(100),
  93. @StockDetailsFooter NVARCHAR(100),
  94. @StartSampleTime DATETIME,
  95. @FinishSampleTime DATETIME,
  96. @ServiceName sysname,
  97. @OutputTableNameFileStats_View NVARCHAR(256),
  98. @OutputTableNamePerfmonStats_View NVARCHAR(256),
  99. @OutputTableNameWaitStats_View NVARCHAR(256),
  100. @ObjectFullName NVARCHAR(2000);
  101.  
  102. /* Sanitize our inputs */
  103. SELECT
  104. @OutputTableNameFileStats_View = QUOTENAME(@OutputTableNameFileStats + '_Deltas'),
  105. @OutputTableNamePerfmonStats_View = QUOTENAME(@OutputTableNamePerfmonStats + '_Deltas'),
  106. @OutputTableNameWaitStats_View = QUOTENAME(@OutputTableNameWaitStats + '_Deltas');
  107.  
  108. SELECT
  109. @OutputDatabaseName = QUOTENAME(@OutputDatabaseName),
  110. @OutputSchemaName = QUOTENAME(@OutputSchemaName),
  111. @OutputTableName = QUOTENAME(@OutputTableName),
  112. @OutputTableNameFileStats = QUOTENAME(@OutputTableNameFileStats),
  113. @OutputTableNamePerfmonStats = QUOTENAME(@OutputTableNamePerfmonStats),
  114. @OutputTableNameWaitStats = QUOTENAME(@OutputTableNameWaitStats),
  115. @LineFeed = CHAR(13) + CHAR(10),
  116. @StartSampleTime = GETDATE(),
  117. @FinishSampleTime = DATEADD(ss, @Seconds, GETDATE()),
  118. @OurSessionID = @@SPID
  119.  
  120.  
  121. IF @Seconds = 0 AND CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) = 'SQL Azure'
  122. SELECT @StartSampleTime = DATEADD(ms, AVG(-wait_time_ms), GETDATE()), @FinishSampleTime = GETDATE()
  123. FROM sys.dm_os_wait_stats w
  124. WHERE wait_type IN ('BROKER_TASK_STOP','DIRTY_PAGE_POLL','HADR_FILESTREAM_IOMGR_IOCOMPLETION','LAZYWRITER_SLEEP',
  125. 'LOGMGR_QUEUE','REQUEST_FOR_DEADLOCK_SEARCH','XE_DISPATCHER_WAIT','XE_TIMER_EVENT')
  126. ELSE IF @Seconds = 0 AND CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) <> 'SQL Azure'
  127. SELECT @StartSampleTime = create_date , @FinishSampleTime = GETDATE()
  128. FROM sys.databases
  129. WHERE database_id = 2;
  130. ELSE
  131. SELECT @StartSampleTime = GETDATE(), @FinishSampleTime = DATEADD(ss, @Seconds, GETDATE());
  132.  
  133. IF @OutputType = 'SCHEMA'
  134. BEGIN
  135. SELECT @Version AS Version,
  136. FieldList = '[Priority] TINYINT, [FindingsGroup] VARCHAR(50), [Finding] VARCHAR(200), [URL] VARCHAR(200), [Details] NVARCHAR(4000), [HowToStopIt] NVARCHAR(MAX), [QueryPlan] XML, [QueryText] NVARCHAR(MAX)'
  137.  
  138. END
  139. ELSE IF @AsOf IS NOT NULL AND @OutputDatabaseName IS NOT NULL AND @OutputSchemaName IS NOT NULL AND @OutputTableName IS NOT NULL
  140. BEGIN
  141. /* They want to look into the past. */
  142.  
  143. SET @StringToExecute = N' IF EXISTS(SELECT * FROM '
  144. + @OutputDatabaseName
  145. + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
  146. + @OutputSchemaName + ''') SELECT CheckDate, [Priority], [FindingsGroup], [Finding], [URL], CAST([Details] AS [XML]) AS Details,'
  147. + '[HowToStopIt], [CheckID], [StartTime], [LoginName], [NTUserName], [OriginalLoginName], [ProgramName], [HostName], [DatabaseID],'
  148. + '[DatabaseName], [OpenTransactionCount], [QueryPlan], [QueryText] FROM '
  149. + @OutputDatabaseName + '.'
  150. + @OutputSchemaName + '.'
  151. + @OutputTableName
  152. + ' WHERE CheckDate >= DATEADD(mi, -15, ''' + CAST(@AsOf AS NVARCHAR(100)) + ''')'
  153. + ' AND CheckDate <= DATEADD(mi, 15, ''' + CAST(@AsOf AS NVARCHAR(100)) + ''')'
  154. + ' /*ORDER BY CheckDate, Priority , FindingsGroup , Finding , Details*/;';
  155. EXEC(@StringToExecute);
  156.  
  157.  
  158. END /* IF @AsOf IS NOT NULL AND @OutputDatabaseName IS NOT NULL AND @OutputSchemaName IS NOT NULL AND @OutputTableName IS NOT NULL */
  159. ELSE IF @Question IS NULL /* IF @OutputType = 'SCHEMA' */
  160. BEGIN
  161.  
  162.  
  163. /*
  164. We start by creating #AskBrentResults. It's a temp table that will storef
  165. the results from our checks. Throughout the rest of this stored procedure,
  166. we're running a series of checks looking for dangerous things inside the SQL
  167. Server. When we find a problem, we insert rows into #BlitzResults. At the
  168. end, we return these results to the end user.
  169.  
  170. #AskBrentResults has a CheckID field, but there's no Check table. As we do
  171. checks, we insert data into this table, and we manually put in the CheckID.
  172. We (Brent Ozar Unlimited) maintain a list of the checks by ID#. You can
  173. download that from http://www.BrentOzar.com/askbrent/documentation/ if you
  174. want to build a tool that relies on the output of sp_AskBrent.
  175. */
  176.  
  177. IF OBJECT_ID('tempdb..#AskBrentResults') IS NOT NULL
  178. DROP TABLE #AskBrentResults;
  179. CREATE TABLE #AskBrentResults
  180. (
  181. ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
  182. CheckID INT NOT NULL,
  183. Priority TINYINT NOT NULL,
  184. FindingsGroup VARCHAR(50) NOT NULL,
  185. Finding VARCHAR(200) NOT NULL,
  186. URL VARCHAR(200) NULL,
  187. Details NVARCHAR(4000) NULL,
  188. HowToStopIt NVARCHAR(MAX) NULL,
  189. QueryPlan [XML] NULL,
  190. QueryText NVARCHAR(MAX) NULL,
  191. StartTime DATETIME NULL,
  192. LoginName NVARCHAR(128) NULL,
  193. NTUserName NVARCHAR(128) NULL,
  194. OriginalLoginName NVARCHAR(128) NULL,
  195. ProgramName NVARCHAR(128) NULL,
  196. HostName NVARCHAR(128) NULL,
  197. DatabaseID INT NULL,
  198. DatabaseName NVARCHAR(128) NULL,
  199. OpenTransactionCount INT NULL,
  200. QueryStatsNowID INT NULL,
  201. QueryStatsFirstID INT NULL,
  202. PlanHandle VARBINARY(64) NULL,
  203. DetailsInt INT NULL,
  204. );
  205.  
  206. IF OBJECT_ID('tempdb..#WaitStats') IS NOT NULL
  207. DROP TABLE #WaitStats;
  208. 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);
  209.  
  210. IF OBJECT_ID('tempdb..#FileStats') IS NOT NULL
  211. DROP TABLE #FileStats;
  212. CREATE TABLE #FileStats (
  213. ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
  214. Pass TINYINT NOT NULL,
  215. SampleTime DATETIME NOT NULL,
  216. DatabaseID INT NOT NULL,
  217. FileID INT NOT NULL,
  218. DatabaseName NVARCHAR(256) ,
  219. FileLogicalName NVARCHAR(256) ,
  220. TypeDesc NVARCHAR(60) ,
  221. SizeOnDiskMB BIGINT ,
  222. io_stall_read_ms BIGINT ,
  223. num_of_reads BIGINT ,
  224. bytes_read BIGINT ,
  225. io_stall_write_ms BIGINT ,
  226. num_of_writes BIGINT ,
  227. bytes_written BIGINT,
  228. PhysicalName NVARCHAR(520) ,
  229. avg_stall_read_ms INT ,
  230. avg_stall_write_ms INT
  231. );
  232.  
  233. IF OBJECT_ID('tempdb..#QueryStats') IS NOT NULL
  234. DROP TABLE #QueryStats;
  235. CREATE TABLE #QueryStats (
  236. ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
  237. Pass INT NOT NULL,
  238. SampleTime DATETIME NOT NULL,
  239. [sql_handle] VARBINARY(64),
  240. statement_start_offset INT,
  241. statement_end_offset INT,
  242. plan_generation_num BIGINT,
  243. plan_handle VARBINARY(64),
  244. execution_count BIGINT,
  245. total_worker_time BIGINT,
  246. total_physical_reads BIGINT,
  247. total_logical_writes BIGINT,
  248. total_logical_reads BIGINT,
  249. total_clr_time BIGINT,
  250. total_elapsed_time BIGINT,
  251. creation_time DATETIME,
  252. query_hash BINARY(8),
  253. query_plan_hash BINARY(8),
  254. Points TINYINT
  255. );
  256.  
  257. IF OBJECT_ID('tempdb..#PerfmonStats') IS NOT NULL
  258. DROP TABLE #PerfmonStats;
  259. CREATE TABLE #PerfmonStats (
  260. ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
  261. Pass TINYINT NOT NULL,
  262. SampleTime DATETIME NOT NULL,
  263. [object_name] NVARCHAR(128) NOT NULL,
  264. [counter_name] NVARCHAR(128) NOT NULL,
  265. [instance_name] NVARCHAR(128) NULL,
  266. [cntr_value] BIGINT NULL,
  267. [cntr_type] INT NOT NULL,
  268. [value_delta] BIGINT NULL,
  269. [value_per_second] DECIMAL(18,2) NULL
  270. );
  271.  
  272. IF OBJECT_ID('tempdb..#PerfmonCounters') IS NOT NULL
  273. DROP TABLE #PerfmonCounters;
  274. CREATE TABLE #PerfmonCounters (
  275. ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
  276. [object_name] NVARCHAR(128) NOT NULL,
  277. [counter_name] NVARCHAR(128) NOT NULL,
  278. [instance_name] NVARCHAR(128) NULL
  279. );
  280.  
  281. IF OBJECT_ID('tempdb..#FilterPlansByDatabase') IS NOT NULL
  282. DROP TABLE #FilterPlansByDatabase;
  283. CREATE TABLE #FilterPlansByDatabase (DatabaseID INT PRIMARY KEY CLUSTERED);
  284.  
  285. IF OBJECT_ID('tempdb..#MasterFiles') IS NOT NULL
  286. DROP TABLE #MasterFiles;
  287. CREATE TABLE #MasterFiles (database_id INT, file_id INT, type_desc NVARCHAR(50), name NVARCHAR(255), physical_name NVARCHAR(255), size BIGINT);
  288. /* Azure SQL Database doesn't have sys.master_files, so we have to build our own. */
  289. IF CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) = 'SQL Azure'
  290. SET @StringToExecute = 'INSERT INTO #MasterFiles (database_id, file_id, type_desc, name, physical_name, size) SELECT DB_ID(), file_id, type_desc, name, physical_name, size FROM sys.database_files;'
  291. ELSE
  292. SET @StringToExecute = 'INSERT INTO #MasterFiles (database_id, file_id, type_desc, name, physical_name, size) SELECT database_id, file_id, type_desc, name, physical_name, size FROM sys.master_files;'
  293. EXEC(@StringToExecute);
  294.  
  295. IF @FilterPlansByDatabase IS NOT NULL
  296. BEGIN
  297. IF UPPER(LEFT(@FilterPlansByDatabase,4)) = 'USER'
  298. BEGIN
  299. INSERT INTO #FilterPlansByDatabase (DatabaseID)
  300. SELECT database_id
  301. FROM sys.databases
  302. WHERE [name] NOT IN ('master', 'model', 'msdb', 'tempdb')
  303. END
  304. ELSE
  305. BEGIN
  306. SET @FilterPlansByDatabase = @FilterPlansByDatabase + ','
  307. ;WITH a AS
  308. (
  309. SELECT CAST(1 AS BIGINT) f, CHARINDEX(',', @FilterPlansByDatabase) t, 1 SEQ
  310. UNION ALL
  311. SELECT t + 1, CHARINDEX(',', @FilterPlansByDatabase, t + 1), SEQ + 1
  312. FROM a
  313. WHERE CHARINDEX(',', @FilterPlansByDatabase, t + 1) > 0
  314. )
  315. INSERT #FilterPlansByDatabase (DatabaseID)
  316. SELECT SUBSTRING(@FilterPlansByDatabase, f, t - f)
  317. FROM a
  318. WHERE SUBSTRING(@FilterPlansByDatabase, f, t - f) IS NOT NULL
  319. OPTION (MAXRECURSION 0)
  320. END
  321. END
  322.  
  323.  
  324. SET @StockWarningHeader = '<?ClickToSeeCommmand -- ' + @LineFeed + @LineFeed
  325. + 'WARNING: Running this command may result in data loss or an outage.' + @LineFeed
  326. + 'This tool is meant as a shortcut to help generate scripts for DBAs.' + @LineFeed
  327. + 'It is not a substitute for database training and experience.' + @LineFeed
  328. + 'Now, having said that, here''s the details:' + @LineFeed + @LineFeed;
  329.  
  330. SELECT @StockWarningFooter = @LineFeed + @LineFeed + '-- ?>',
  331. @StockDetailsHeader = '<?ClickToSeeDetails -- ' + @LineFeed,
  332. @StockDetailsFooter = @LineFeed + ' -- ?>';
  333.  
  334. /* Get the instance name to use as a Perfmon counter prefix. */
  335. IF CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) = 'SQL Azure'
  336. SELECT TOP 1 @ServiceName = LEFT(object_name, (CHARINDEX(':', object_name) - 1))
  337. FROM sys.dm_os_performance_counters;
  338. ELSE
  339. BEGIN
  340. SET @StringToExecute = 'INSERT INTO #PerfmonStats(object_name, Pass, SampleTime, counter_name, cntr_type) SELECT CASE WHEN @@SERVICENAME = ''MSSQLSERVER'' THEN ''SQLServer'' ELSE ''MSSQL$'' + @@SERVICENAME END, 0, GETDATE(), ''stuffing'', 0 ;'
  341. EXEC(@StringToExecute);
  342. SELECT @ServiceName = object_name FROM #PerfmonStats;
  343. DELETE #PerfmonStats;
  344. END
  345.  
  346. /* Build a list of queries that were run in the last 10 seconds.
  347. We're looking for the death-by-a-thousand-small-cuts scenario
  348. where a query is constantly running, and it doesn't have that
  349. big of an impact individually, but it has a ton of impact
  350. overall. We're going to build this list, and then after we
  351. finish our @Seconds sample, we'll compare our plan cache to
  352. this list to see what ran the most. */
  353.  
  354. /* Populate #QueryStats. SQL 2005 doesn't have query hash or query plan hash. */
  355. IF @@VERSION LIKE 'Microsoft SQL Server 2005%'
  356. BEGIN
  357. IF @FilterPlansByDatabase IS NULL
  358. BEGIN
  359. 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)
  360. 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
  361. FROM sys.dm_exec_query_stats qs
  362. WHERE qs.last_execution_time >= (DATEADD(ss, -10, GETDATE()));';
  363. END
  364. ELSE
  365. BEGIN
  366. 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)
  367. 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
  368. FROM sys.dm_exec_query_stats qs
  369. CROSS APPLY sys.dm_exec_plan_attributes(qs.plan_handle) AS attr
  370. INNER JOIN #FilterPlansByDatabase dbs ON CAST(attr.value AS INT) = dbs.DatabaseID
  371. WHERE qs.last_execution_time >= (DATEADD(ss, -10, GETDATE()))
  372. AND attr.attribute = ''dbid'';';
  373. END
  374. END
  375. ELSE
  376. BEGIN
  377. IF @FilterPlansByDatabase IS NULL
  378. BEGIN
  379. 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)
  380. 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
  381. FROM sys.dm_exec_query_stats qs
  382. WHERE qs.last_execution_time >= (DATEADD(ss, -10, GETDATE()));';
  383. END
  384. ELSE
  385. BEGIN
  386. 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)
  387. 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
  388. FROM sys.dm_exec_query_stats qs
  389. CROSS APPLY sys.dm_exec_plan_attributes(qs.plan_handle) AS attr
  390. INNER JOIN #FilterPlansByDatabase dbs ON CAST(attr.value AS INT) = dbs.DatabaseID
  391. WHERE qs.last_execution_time >= (DATEADD(ss, -10, GETDATE()))
  392. AND attr.attribute = ''dbid'';';
  393. END
  394. END
  395. IF @SkipChecksQueries = 0 EXEC(@StringToExecute);
  396.  
  397. /* Get the totals for the entire plan cache */
  398. 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)
  399. 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)
  400. FROM sys.dm_exec_query_stats qs;
  401.  
  402.  
  403. IF EXISTS (SELECT *
  404. FROM tempdb.sys.all_objects obj
  405. INNER JOIN tempdb.sys.all_columns col1 ON obj.object_id = col1.object_id AND col1.name = 'object_name'
  406. INNER JOIN tempdb.sys.all_columns col2 ON obj.object_id = col2.object_id AND col2.name = 'counter_name'
  407. INNER JOIN tempdb.sys.all_columns col3 ON obj.object_id = col3.object_id AND col3.name = 'instance_name'
  408. WHERE obj.name LIKE '%CustomPerfmonCounters%')
  409. BEGIN
  410. SET @StringToExecute = 'INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) SELECT [object_name],[counter_name],[instance_name] FROM #CustomPerfmonCounters'
  411. EXEC(@StringToExecute);
  412. END
  413. ELSE
  414. BEGIN
  415. /* Add our default Perfmon counters */
  416. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Access Methods','Forwarded Records/sec', NULL)
  417. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Access Methods','Page compression attempts/sec', NULL)
  418. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Access Methods','Page Splits/sec', NULL)
  419. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Access Methods','Skipped Ghosted Records/sec', NULL)
  420. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Access Methods','Table Lock Escalations/sec', NULL)
  421. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Access Methods','Worktables Created/sec', NULL)
  422. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Page life expectancy', NULL)
  423. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Page reads/sec', NULL)
  424. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Page writes/sec', NULL)
  425. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Readahead pages/sec', NULL)
  426. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Target pages', NULL)
  427. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Total pages', NULL)
  428. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Databases','', NULL)
  429. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Active Transactions','_Total')
  430. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Databases','Log Growths', '_Total')
  431. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Databases','Log Shrinks', '_Total')
  432. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Exec Statistics','Distributed Query', 'Execs in progress')
  433. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Exec Statistics','DTC calls', 'Execs in progress')
  434. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Exec Statistics','Extended Procedures', 'Execs in progress')
  435. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Exec Statistics','OLEDB calls', 'Execs in progress')
  436. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':General Statistics','Active Temp Tables', NULL)
  437. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':General Statistics','Logins/sec', NULL)
  438. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':General Statistics','Logouts/sec', NULL)
  439. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':General Statistics','Mars Deadlocks', NULL)
  440. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':General Statistics','Processes blocked', NULL)
  441. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Locks','Number of Deadlocks/sec', NULL)
  442. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Memory Manager','Memory Grants Pending', NULL)
  443. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Errors','Errors/sec', '_Total')
  444. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','Batch Requests/sec', NULL)
  445. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','Forced Parameterizations/sec', NULL)
  446. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','Guided plan executions/sec', NULL)
  447. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','SQL Attention rate', NULL)
  448. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','SQL Compilations/sec', NULL)
  449. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','SQL Re-Compilations/sec', NULL)
  450. /* Below counters added by Jefferson Elias */
  451. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Access Methods','Worktables From Cache Base',NULL)
  452. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Access Methods','Worktables From Cache Ratio',NULL)
  453. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Database pages',NULL)
  454. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Free pages',NULL)
  455. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Stolen pages',NULL)
  456. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Memory Manager','Granted Workspace Memory (KB)',NULL)
  457. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Memory Manager','Maximum Workspace Memory (KB)',NULL)
  458. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Memory Manager','Target Server Memory (KB)',NULL)
  459. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Memory Manager','Total Server Memory (KB)',NULL)
  460. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Buffer cache hit ratio',NULL)
  461. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Buffer cache hit ratio base',NULL)
  462. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Checkpoint pages/sec',NULL)
  463. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Free list stalls/sec',NULL)
  464. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Lazy writes/sec',NULL)
  465. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','Auto-Param Attempts/sec',NULL)
  466. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','Failed Auto-Params/sec',NULL)
  467. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','Safe Auto-Params/sec',NULL)
  468. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','Unsafe Auto-Params/sec',NULL)
  469. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Access Methods','Workfiles Created/sec',NULL)
  470. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':General Statistics','User Connections',NULL)
  471. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Latches','Average Latch Wait Time (ms)',NULL)
  472. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Latches','Average Latch Wait Time Base',NULL)
  473. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Latches','Latch Waits/sec',NULL)
  474. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Latches','Total Latch Wait Time (ms)',NULL)
  475. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Locks','Average Wait Time (ms)',NULL)
  476. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Locks','Average Wait Time Base',NULL)
  477. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Locks','Lock Requests/sec',NULL)
  478. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Locks','Lock Timeouts/sec',NULL)
  479. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Locks','Lock Wait Time (ms)',NULL)
  480. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Locks','Lock Waits/sec',NULL)
  481. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Transactions','Longest Transaction Running Time',NULL)
  482. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Access Methods','Full Scans/sec',NULL)
  483. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Access Methods','Index Searches/sec',NULL)
  484. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Buffer Manager','Page lookups/sec',NULL)
  485. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':Cursor Manager by Type','Active cursors',NULL)
  486. END
  487.  
  488. /* Populate #FileStats, #PerfmonStats, #WaitStats with DMV data.
  489. After we finish doing our checks, we'll take another sample and compare them. */
  490. INSERT #WaitStats(Pass, SampleTime, wait_type, wait_time_ms, signal_wait_time_ms, waiting_tasks_count)
  491. SELECT
  492. 1 AS Pass,
  493. CASE @Seconds WHEN 0 THEN @StartSampleTime ELSE GETDATE() END AS SampleTime,
  494. os.wait_type,
  495. CASE @Seconds WHEN 0 THEN 0 ELSE SUM(os.wait_time_ms) OVER (PARTITION BY os.wait_type) END as sum_wait_time_ms,
  496. CASE @Seconds WHEN 0 THEN 0 ELSE SUM(os.signal_wait_time_ms) OVER (PARTITION BY os.wait_type ) END as sum_signal_wait_time_ms,
  497. CASE @Seconds WHEN 0 THEN 0 ELSE SUM(os.waiting_tasks_count) OVER (PARTITION BY os.wait_type) END AS sum_waiting_tasks
  498. FROM sys.dm_os_wait_stats os
  499. WHERE os.wait_type not in (
  500. 'REQUEST_FOR_DEADLOCK_SEARCH',
  501. 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
  502. 'SQLTRACE_BUFFER_FLUSH',
  503. 'LAZYWRITER_SLEEP',
  504. 'XE_TIMER_EVENT',
  505. 'XE_DISPATCHER_WAIT',
  506. 'FT_IFTS_SCHEDULER_IDLE_WAIT',
  507. 'LOGMGR_QUEUE',
  508. 'CHECKPOINT_QUEUE',
  509. 'BROKER_TO_FLUSH',
  510. 'BROKER_TASK_STOP',
  511. 'BROKER_EVENTHANDLER',
  512. 'SLEEP_TASK',
  513. 'WAITFOR',
  514. 'DBMIRROR_DBM_MUTEX',
  515. 'DBMIRROR_EVENTS_QUEUE',
  516. 'DBMIRRORING_CMD',
  517. 'DISPATCHER_QUEUE_SEMAPHORE',
  518. 'BROKER_RECEIVE_WAITFOR',
  519. 'CLR_AUTO_EVENT',
  520. 'DIRTY_PAGE_POLL',
  521. 'HADR_FILESTREAM_IOMGR_IOCOMPLETION',
  522. 'ONDEMAND_TASK_QUEUE',
  523. 'FT_IFTSHC_MUTEX',
  524. 'CLR_MANUAL_EVENT',
  525. 'CLR_SEMAPHORE',
  526. 'DBMIRROR_WORKER_QUEUE',
  527. 'DBMIRROR_DBM_EVENT',
  528. 'SP_SERVER_DIAGNOSTICS_SLEEP',
  529. 'HADR_CLUSAPI_CALL',
  530. 'HADR_LOGCAPTURE_WAIT',
  531. 'HADR_NOTIFICATION_DEQUEUE',
  532. 'HADR_TIMER_TASK',
  533. 'HADR_WORK_QUEUE',
  534. 'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP',
  535. 'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP',
  536. 'RESOURCE_GOVERNOR_IDLE',
  537. 'QDS_ASYNC_QUEUE',
  538. 'QDS_SHUTDOWN_QUEUE',
  539. 'SLEEP_SYSTEMTASK'
  540. )
  541. ORDER BY sum_wait_time_ms DESC;
  542.  
  543.  
  544. INSERT INTO #FileStats (Pass, SampleTime, DatabaseID, FileID, DatabaseName, FileLogicalName, SizeOnDiskMB, io_stall_read_ms ,
  545. num_of_reads, [bytes_read] , io_stall_write_ms,num_of_writes, [bytes_written], PhysicalName, TypeDesc)
  546. SELECT
  547. 1 AS Pass,
  548. CASE @Seconds WHEN 0 THEN @StartSampleTime ELSE GETDATE() END AS SampleTime,
  549. mf.[database_id],
  550. mf.[file_id],
  551. DB_NAME(vfs.database_id) AS [db_name],
  552. mf.name + N' [' + mf.type_desc COLLATE SQL_Latin1_General_CP1_CI_AS + N']' AS file_logical_name ,
  553. CAST(( ( vfs.size_on_disk_bytes / 1024.0 ) / 1024.0 ) AS INT) AS size_on_disk_mb ,
  554. CASE @Seconds WHEN 0 THEN 0 ELSE vfs.io_stall_read_ms END ,
  555. CASE @Seconds WHEN 0 THEN 0 ELSE vfs.num_of_reads END ,
  556. CASE @Seconds WHEN 0 THEN 0 ELSE vfs.[num_of_bytes_read] END ,
  557. CASE @Seconds WHEN 0 THEN 0 ELSE vfs.io_stall_write_ms END ,
  558. CASE @Seconds WHEN 0 THEN 0 ELSE vfs.num_of_writes END ,
  559. CASE @Seconds WHEN 0 THEN 0 ELSE vfs.[num_of_bytes_written] END ,
  560. mf.physical_name,
  561. mf.type_desc
  562. FROM sys.dm_io_virtual_file_stats (NULL, NULL) AS vfs
  563. INNER JOIN #MasterFiles AS mf ON vfs.file_id = mf.file_id
  564. AND vfs.database_id = mf.database_id
  565. WHERE vfs.num_of_reads > 0
  566. OR vfs.num_of_writes > 0;
  567.  
  568. INSERT INTO #PerfmonStats (Pass, SampleTime, [object_name],[counter_name],[instance_name],[cntr_value],[cntr_type])
  569. SELECT 1 AS Pass,
  570. CASE @Seconds WHEN 0 THEN @StartSampleTime ELSE GETDATE() END AS SampleTime, RTRIM(dmv.object_name), RTRIM(dmv.counter_name), RTRIM(dmv.instance_name), CASE @Seconds WHEN 0 THEN 0 ELSE dmv.cntr_value END, dmv.cntr_type
  571. FROM #PerfmonCounters counters
  572. INNER JOIN sys.dm_os_performance_counters dmv ON counters.counter_name COLLATE SQL_Latin1_General_CP1_CI_AS = RTRIM(dmv.counter_name) COLLATE SQL_Latin1_General_CP1_CI_AS
  573. AND counters.[object_name] COLLATE SQL_Latin1_General_CP1_CI_AS = RTRIM(dmv.[object_name]) COLLATE SQL_Latin1_General_CP1_CI_AS
  574. AND (counters.[instance_name] IS NULL OR counters.[instance_name] COLLATE SQL_Latin1_General_CP1_CI_AS = RTRIM(dmv.[instance_name]) COLLATE SQL_Latin1_General_CP1_CI_AS)
  575.  
  576. /* Maintenance Tasks Running - Backup Running - CheckID 1 */
  577. IF @Seconds > 0
  578. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
  579. SELECT 1 AS CheckID,
  580. 1 AS Priority,
  581. 'Maintenance Tasks Running' AS FindingGroup,
  582. 'Backup Running' AS Finding,
  583. 'http://www.BrentOzar.com/askbrent/backups/' AS URL,
  584. 'Backup of ' + DB_NAME(db.resource_database_id) + ' database (' + (SELECT CAST(CAST(SUM(size * 8.0 / 1024 / 1024) AS BIGINT) AS NVARCHAR) FROM #MasterFiles 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,
  585. 'KILL ' + CAST(r.session_id AS NVARCHAR(100)) + ';' AS HowToStopIt,
  586. pl.query_plan AS QueryPlan,
  587. r.start_time AS StartTime,
  588. s.login_name AS LoginName,
  589. s.nt_user_name AS NTUserName,
  590. s.[program_name] AS ProgramName,
  591. s.[host_name] AS HostName,
  592. db.[resource_database_id] AS DatabaseID,
  593. DB_NAME(db.resource_database_id) AS DatabaseName,
  594. 0 AS OpenTransactionCount
  595. FROM sys.dm_exec_requests r
  596. INNER JOIN sys.dm_exec_connections c ON r.session_id = c.session_id
  597. INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
  598. INNER JOIN (
  599. SELECT DISTINCT request_session_id, resource_database_id
  600. FROM sys.dm_tran_locks
  601. WHERE resource_type = N'DATABASE'
  602. AND request_mode = N'S'
  603. AND request_status = N'GRANT'
  604. AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
  605. CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
  606. WHERE r.command LIKE 'BACKUP%';
  607.  
  608.  
  609. /* If there's a backup running, add details explaining how long full backup has been taking in the last month. */
  610. IF @Seconds > 0 AND CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) <> 'SQL Azure'
  611. BEGIN
  612. SET @StringToExecute = 'UPDATE #AskBrentResults 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.'' FROM #AskBrentResults abr 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)';
  613. EXEC(@StringToExecute);
  614. END
  615.  
  616.  
  617. /* Maintenance Tasks Running - DBCC Running - CheckID 2 */
  618. IF @Seconds > 0
  619. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
  620. SELECT 2 AS CheckID,
  621. 1 AS Priority,
  622. 'Maintenance Tasks Running' AS FindingGroup,
  623. 'DBCC Running' AS Finding,
  624. 'http://www.BrentOzar.com/askbrent/dbcc/' AS URL,
  625. 'Corruption check of ' + DB_NAME(db.resource_database_id) + ' database (' + (SELECT CAST(CAST(SUM(size * 8.0 / 1024 / 1024) AS BIGINT) AS NVARCHAR) FROM #MasterFiles WHERE database_id = db.resource_database_id) + 'GB) has been running since ' + CAST(r.start_time AS NVARCHAR(100)) + '. ' AS Details,
  626. 'KILL ' + CAST(r.session_id AS NVARCHAR(100)) + ';' AS HowToStopIt,
  627. pl.query_plan AS QueryPlan,
  628. r.start_time AS StartTime,
  629. s.login_name AS LoginName,
  630. s.nt_user_name AS NTUserName,
  631. s.[program_name] AS ProgramName,
  632. s.[host_name] AS HostName,
  633. db.[resource_database_id] AS DatabaseID,
  634. DB_NAME(db.resource_database_id) AS DatabaseName,
  635. 0 AS OpenTransactionCount
  636. FROM sys.dm_exec_requests r
  637. INNER JOIN sys.dm_exec_connections c ON r.session_id = c.session_id
  638. INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
  639. INNER JOIN (SELECT DISTINCT l.request_session_id, l.resource_database_id
  640. FROM sys.dm_tran_locks l
  641. INNER JOIN sys.databases d ON l.resource_database_id = d.database_id
  642. WHERE l.resource_type = N'DATABASE'
  643. AND l.request_mode = N'S'
  644. AND l.request_status = N'GRANT'
  645. AND l.request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
  646. CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
  647. WHERE r.command LIKE 'DBCC%';
  648.  
  649.  
  650. /* Maintenance Tasks Running - Restore Running - CheckID 3 */
  651. IF @Seconds > 0
  652. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
  653. SELECT 3 AS CheckID,
  654. 1 AS Priority,
  655. 'Maintenance Tasks Running' AS FindingGroup,
  656. 'Restore Running' AS Finding,
  657. 'http://www.BrentOzar.com/askbrent/backups/' AS URL,
  658. 'Restore of ' + DB_NAME(db.resource_database_id) + ' database (' + (SELECT CAST(CAST(SUM(size * 8.0 / 1024 / 1024) AS BIGINT) AS NVARCHAR) FROM #MasterFiles 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,
  659. 'KILL ' + CAST(r.session_id AS NVARCHAR(100)) + ';' AS HowToStopIt,
  660. pl.query_plan AS QueryPlan,
  661. r.start_time AS StartTime,
  662. s.login_name AS LoginName,
  663. s.nt_user_name AS NTUserName,
  664. s.[program_name] AS ProgramName,
  665. s.[host_name] AS HostName,
  666. db.[resource_database_id] AS DatabaseID,
  667. DB_NAME(db.resource_database_id) AS DatabaseName,
  668. 0 AS OpenTransactionCount
  669. FROM sys.dm_exec_requests r
  670. INNER JOIN sys.dm_exec_connections c ON r.session_id = c.session_id
  671. INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
  672. INNER JOIN (
  673. SELECT DISTINCT request_session_id, resource_database_id
  674. FROM sys.dm_tran_locks
  675. WHERE resource_type = N'DATABASE'
  676. AND request_mode = N'S'
  677. AND request_status = N'GRANT'
  678. AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
  679. CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
  680. WHERE r.command LIKE 'RESTORE%';
  681.  
  682.  
  683. /* SQL Server Internal Maintenance - Database File Growing - CheckID 4 */
  684. IF @Seconds > 0
  685. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
  686. SELECT 4 AS CheckID,
  687. 1 AS Priority,
  688. 'SQL Server Internal Maintenance' AS FindingGroup,
  689. 'Database File Growing' AS Finding,
  690. 'http://www.BrentOzar.com/go/instant' AS URL,
  691. '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,
  692. 'Unfortunately, you can''t stop this, but you can prevent it next time. Check out http://www.BrentOzar.com/go/instant for details.' AS HowToStopIt,
  693. pl.query_plan AS QueryPlan,
  694. r.start_time AS StartTime,
  695. s.login_name AS LoginName,
  696. s.nt_user_name AS NTUserName,
  697. s.[program_name] AS ProgramName,
  698. s.[host_name] AS HostName,
  699. NULL AS DatabaseID,
  700. NULL AS DatabaseName,
  701. 0 AS OpenTransactionCount
  702. FROM sys.dm_os_waiting_tasks t
  703. INNER JOIN sys.dm_exec_connections c ON t.session_id = c.session_id
  704. INNER JOIN sys.dm_exec_requests r ON t.session_id = r.session_id
  705. INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
  706. CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
  707. WHERE t.wait_type = 'PREEMPTIVE_OS_WRITEFILEGATHER'
  708.  
  709.  
  710. /* Query Problems - Long-Running Query Blocking Others - CheckID 5 */
  711. /*
  712. IF @Seconds > 0
  713. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
  714. SELECT 5 AS CheckID,
  715. 1 AS Priority,
  716. 'Query Problems' AS FindingGroup,
  717. 'Long-Running Query Blocking Others' AS Finding,
  718. 'http://www.BrentOzar.com/go/blocking' AS URL,
  719. 'Query in ' + DB_NAME(db.resource_database_id) + ' has been running since ' + CAST(r.start_time AS NVARCHAR(100)) + '. ' + @LineFeed + @LineFeed
  720. + CAST(COALESCE((SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(rBlocker.sql_handle)),
  721. (SELECT TOP 1 [text] FROM master..sysprocesses spBlocker CROSS APPLY sys.dm_exec_sql_text(spBlocker.sql_handle) WHERE spBlocker.spid = tBlocked.blocking_session_id), '') AS NVARCHAR(2000)) AS Details,
  722. 'KILL ' + CAST(tBlocked.blocking_session_id AS NVARCHAR(100)) + ';' AS HowToStopIt,
  723. (SELECT TOP 1 query_plan FROM sys.dm_exec_query_plan(rBlocker.plan_handle)) AS QueryPlan,
  724. COALESCE((SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(rBlocker.sql_handle)),
  725. (SELECT TOP 1 [text] FROM master..sysprocesses spBlocker CROSS APPLY sys.dm_exec_sql_text(spBlocker.sql_handle) WHERE spBlocker.spid = tBlocked.blocking_session_id)) AS QueryText,
  726. r.start_time AS StartTime,
  727. s.login_name AS LoginName,
  728. s.nt_user_name AS NTUserName,
  729. s.[program_name] AS ProgramName,
  730. s.[host_name] AS HostName,
  731. db.[resource_database_id] AS DatabaseID,
  732. DB_NAME(db.resource_database_id) AS DatabaseName,
  733. 0 AS OpenTransactionCount
  734. FROM sys.dm_exec_sessions s
  735. INNER JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
  736. INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
  737. INNER JOIN sys.dm_os_waiting_tasks tBlocked ON tBlocked.session_id = s.session_id AND tBlocked.session_id <> s.session_id
  738. INNER JOIN (
  739. SELECT DISTINCT request_session_id, resource_database_id
  740. FROM sys.dm_tran_locks
  741. WHERE resource_type = N'DATABASE'
  742. AND request_mode = N'S'
  743. AND request_status = N'GRANT'
  744. AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
  745. LEFT OUTER JOIN sys.dm_exec_requests rBlocker ON tBlocked.blocking_session_id = rBlocker.session_id
  746. 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)
  747. AND s.last_request_start_time < DATEADD(SECOND, -30, GETDATE())
  748. */
  749.  
  750. /* Query Problems - Plan Cache Erased Recently */
  751. IF DATEADD(mi, -15, GETDATE()) < (SELECT TOP 1 creation_time FROM sys.dm_exec_query_stats ORDER BY creation_time)
  752. BEGIN
  753. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
  754. SELECT TOP 1 7 AS CheckID,
  755. 50 AS Priority,
  756. 'Query Problems' AS FindingGroup,
  757. 'Plan Cache Erased Recently' AS Finding,
  758. 'http://www.BrentOzar.com/askbrent/plan-cache-erased-recently/' AS URL,
  759. 'The oldest query in the plan cache was created at ' + CAST(creation_time AS NVARCHAR(50)) + '. ' + @LineFeed + @LineFeed
  760. + 'This indicates that someone ran DBCC FREEPROCCACHE at that time,' + @LineFeed
  761. + 'Giving SQL Server temporary amnesia. Now, as queries come in,' + @LineFeed
  762. + 'SQL Server has to use a lot of CPU power in order to build execution' + @LineFeed
  763. + 'plans and put them in cache again. This causes high CPU loads.' AS Details,
  764. 'Find who did that, and stop them from doing it again.' AS HowToStopIt
  765. FROM sys.dm_exec_query_stats
  766. ORDER BY creation_time
  767. END;
  768.  
  769.  
  770. /* Query Problems - Sleeping Query with Open Transactions - CheckID 8 */
  771. IF @Seconds > 0
  772. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, QueryText, OpenTransactionCount)
  773. SELECT 8 AS CheckID,
  774. 50 AS Priority,
  775. 'Query Problems' AS FindingGroup,
  776. 'Sleeping Query with Open Transactions' AS Finding,
  777. 'http://www.brentozar.com/askbrent/sleeping-query-with-open-transactions/' AS URL,
  778. '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,
  779. 'KILL ' + CAST(s.session_id AS NVARCHAR(100)) + ';' AS HowToStopIt,
  780. s.last_request_start_time AS StartTime,
  781. s.login_name AS LoginName,
  782. s.nt_user_name AS NTUserName,
  783. s.[program_name] AS ProgramName,
  784. s.[host_name] AS HostName,
  785. db.[resource_database_id] AS DatabaseID,
  786. DB_NAME(db.resource_database_id) AS DatabaseName,
  787. (SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(c.most_recent_sql_handle)) AS QueryText,
  788. sessions_with_transactions.open_transaction_count AS OpenTransactionCount
  789. 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
  790. INNER JOIN sys.dm_exec_sessions s ON sessions_with_transactions.session_id = s.session_id
  791. INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
  792. INNER JOIN (
  793. SELECT DISTINCT request_session_id, resource_database_id
  794. FROM sys.dm_tran_locks
  795. WHERE resource_type = N'DATABASE'
  796. AND request_mode = N'S'
  797. AND request_status = N'GRANT'
  798. AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
  799. WHERE s.status = 'sleeping'
  800. AND s.last_request_end_time < DATEADD(ss, -10, GETDATE())
  801. AND EXISTS(SELECT * FROM sys.dm_tran_locks WHERE request_session_id = s.session_id
  802. AND NOT (resource_type = N'DATABASE' AND request_mode = N'S' AND request_status = N'GRANT' AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE'))
  803.  
  804.  
  805. /* Query Problems - Query Rolling Back - CheckID 9 */
  806. IF @Seconds > 0
  807. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, QueryText)
  808. SELECT 9 AS CheckID,
  809. 1 AS Priority,
  810. 'Query Problems' AS FindingGroup,
  811. 'Query Rolling Back' AS Finding,
  812. 'http://www.BrentOzar.com/askbrent/rollback/' AS URL,
  813. 'Rollback started at ' + CAST(r.start_time AS NVARCHAR(100)) + ', is ' + CAST(r.percent_complete AS NVARCHAR(100)) + '% complete.' AS Details,
  814. '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,
  815. r.start_time AS StartTime,
  816. s.login_name AS LoginName,
  817. s.nt_user_name AS NTUserName,
  818. s.[program_name] AS ProgramName,
  819. s.[host_name] AS HostName,
  820. db.[resource_database_id] AS DatabaseID,
  821. DB_NAME(db.resource_database_id) AS DatabaseName,
  822. (SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(c.most_recent_sql_handle)) AS QueryText
  823. FROM sys.dm_exec_sessions s
  824. INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
  825. INNER JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
  826. LEFT OUTER JOIN (
  827. SELECT DISTINCT request_session_id, resource_database_id
  828. FROM sys.dm_tran_locks
  829. WHERE resource_type = N'DATABASE'
  830. AND request_mode = N'S'
  831. AND request_status = N'GRANT'
  832. AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
  833. WHERE r.status = 'rollback'
  834.  
  835.  
  836. /* Server Performance - Page Life Expectancy Low - CheckID 10 */
  837. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
  838. SELECT 10 AS CheckID,
  839. 50 AS Priority,
  840. 'Server Performance' AS FindingGroup,
  841. 'Page Life Expectancy Low' AS Finding,
  842. 'http://www.BrentOzar.com/askbrent/page-life-expectancy/' AS URL,
  843. 'SQL Server Buffer Manager:Page life expectancy is ' + CAST(c.cntr_value AS NVARCHAR(10)) + ' seconds.' + @LineFeed
  844. + 'This means SQL Server can only keep data pages in memory for that many seconds after reading those pages in from storage.' + @LineFeed
  845. + 'This is a symptom, not a cause - it indicates very read-intensive queries that need an index, or insufficient server memory.' AS Details,
  846. '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
  847. FROM sys.dm_os_performance_counters c
  848. WHERE object_name LIKE 'SQLServer:Buffer Manager%'
  849. AND counter_name LIKE 'Page life expectancy%'
  850. AND cntr_value < 300
  851.  
  852. /* Server Info - Database Size, Total GB - CheckID 21 */
  853. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, Details, DetailsInt, URL)
  854. SELECT 21 AS CheckID,
  855. 251 AS Priority,
  856. 'Server Info' AS FindingGroup,
  857. 'Database Size, Total GB' AS Finding,
  858. CAST(SUM (CAST(size AS bigint)*8./1024./1024.) AS VARCHAR(100)) AS Details,
  859. SUM (CAST(size AS bigint))*8./1024./1024. AS DetailsInt,
  860. 'http://www.BrentOzar.com/askbrent/' AS URL
  861. FROM #MasterFiles
  862. WHERE database_id > 4
  863.  
  864. /* Server Info - Database Count - CheckID 22 */
  865. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, Details, DetailsInt, URL)
  866. SELECT 22 AS CheckID,
  867. 251 AS Priority,
  868. 'Server Info' AS FindingGroup,
  869. 'Database Count' AS Finding,
  870. CAST(SUM(1) AS VARCHAR(100)) AS Details,
  871. SUM (1) AS DetailsInt,
  872. 'http://www.BrentOzar.com/askbrent/' AS URL
  873. FROM sys.databases
  874. WHERE database_id > 4
  875.  
  876. /* Server Performance - High CPU Utilization CheckID 24 */
  877. IF @Seconds < 30
  878. BEGIN
  879. /* If we're waiting less than 30 seconds, run this check now rather than wait til the end.
  880. We get this data from the ring buffers, and it's only updated once per minute, so might
  881. as well get it now - whereas if we're checking 30+ seconds, it might get updated by the
  882. end of our sp_AskBrent session. */
  883. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, Details, DetailsInt, URL)
  884. SELECT 24, 50, 'Server Performance', 'High CPU Utilization', CAST(100 - SystemIdle AS NVARCHAR(20)) + N'%. Ring buffer details: ' + CAST(record AS NVARCHAR(4000)), 100 - SystemIdle, 'http://www.BrentOzar.com/go/cpu'
  885. FROM (
  886. SELECT record,
  887. record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int') as SystemIdle
  888. FROM (
  889. SELECT TOP 1 CONVERT(XML, record) as record
  890. FROM sys.dm_os_ring_buffers
  891. WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
  892. AND record LIKE '%<SystemHealth>%'
  893. ORDER BY timestamp DESC) AS rb
  894. ) as y
  895. WHERE 100 - SystemIdle >= 50
  896.  
  897. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, Details, DetailsInt, URL)
  898. SELECT 23, 250, 'Server Info', 'CPU Utilization', CAST(100 - SystemIdle AS NVARCHAR(20)) + N'%. Ring buffer details: ' + CAST(record AS NVARCHAR(4000)), 100 - SystemIdle, 'http://www.BrentOzar.com/go/cpu'
  899. FROM (
  900. SELECT record,
  901. record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int') as SystemIdle
  902. FROM (
  903. SELECT TOP 1 CONVERT(XML, record) as record
  904. FROM sys.dm_os_ring_buffers
  905. WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
  906. AND record LIKE '%<SystemHealth>%'
  907. ORDER BY timestamp DESC) AS rb
  908. ) as y
  909.  
  910. END /* IF @Seconds < 30 */
  911.  
  912.  
  913. /* End of checks. If we haven't waited @Seconds seconds, wait. */
  914. IF GETDATE() < @FinishSampleTime
  915. WAITFOR TIME @FinishSampleTime;
  916.  
  917.  
  918. /* Populate #FileStats, #PerfmonStats, #WaitStats with DMV data. In a second, we'll compare these. */
  919. INSERT #WaitStats(Pass, SampleTime, wait_type, wait_time_ms, signal_wait_time_ms, waiting_tasks_count)
  920. SELECT
  921. 2 AS Pass,
  922. GETDATE() AS SampleTime,
  923. os.wait_type,
  924. SUM(os.wait_time_ms) OVER (PARTITION BY os.wait_type) as sum_wait_time_ms,
  925. SUM(os.signal_wait_time_ms) OVER (PARTITION BY os.wait_type ) as sum_signal_wait_time_ms,
  926. SUM(os.waiting_tasks_count) OVER (PARTITION BY os.wait_type) AS sum_waiting_tasks
  927. FROM sys.dm_os_wait_stats os
  928. WHERE os.wait_type not in (
  929. 'REQUEST_FOR_DEADLOCK_SEARCH',
  930. 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
  931. 'SQLTRACE_BUFFER_FLUSH',
  932. 'LAZYWRITER_SLEEP',
  933. 'XE_TIMER_EVENT',
  934. 'XE_DISPATCHER_WAIT',
  935. 'FT_IFTS_SCHEDULER_IDLE_WAIT',
  936. 'LOGMGR_QUEUE',
  937. 'CHECKPOINT_QUEUE',
  938. 'BROKER_TO_FLUSH',
  939. 'BROKER_TASK_STOP',
  940. 'BROKER_EVENTHANDLER',
  941. 'SLEEP_TASK',
  942. 'WAITFOR',
  943. 'DBMIRROR_DBM_MUTEX',
  944. 'DBMIRROR_EVENTS_QUEUE',
  945. 'DBMIRRORING_CMD',
  946. 'DISPATCHER_QUEUE_SEMAPHORE',
  947. 'BROKER_RECEIVE_WAITFOR',
  948. 'CLR_AUTO_EVENT',
  949. 'DIRTY_PAGE_POLL',
  950. 'HADR_FILESTREAM_IOMGR_IOCOMPLETION',
  951. 'ONDEMAND_TASK_QUEUE',
  952. 'FT_IFTSHC_MUTEX',
  953. 'CLR_MANUAL_EVENT',
  954. 'CLR_SEMAPHORE',
  955. 'DBMIRROR_WORKER_QUEUE',
  956. 'DBMIRROR_DBM_EVENT',
  957. 'SP_SERVER_DIAGNOSTICS_SLEEP',
  958. 'HADR_CLUSAPI_CALL',
  959. 'HADR_LOGCAPTURE_WAIT',
  960. 'HADR_NOTIFICATION_DEQUEUE',
  961. 'HADR_TIMER_TASK',
  962. 'HADR_WORK_QUEUE',
  963. 'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP',
  964. 'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP',
  965. 'RESOURCE_GOVERNOR_IDLE',
  966. 'QDS_ASYNC_QUEUE',
  967. 'QDS_SHUTDOWN_QUEUE',
  968. 'SLEEP_SYSTEMTASK'
  969. )
  970. ORDER BY sum_wait_time_ms DESC;
  971.  
  972. INSERT INTO #FileStats (Pass, SampleTime, DatabaseID, FileID, DatabaseName, FileLogicalName, SizeOnDiskMB, io_stall_read_ms ,
  973. num_of_reads, [bytes_read] , io_stall_write_ms,num_of_writes, [bytes_written], PhysicalName, TypeDesc, avg_stall_read_ms, avg_stall_write_ms)
  974. SELECT 2 AS Pass,
  975. GETDATE() AS SampleTime,
  976. mf.[database_id],
  977. mf.[file_id],
  978. DB_NAME(vfs.database_id) AS [db_name],
  979. mf.name + N' [' + mf.type_desc COLLATE SQL_Latin1_General_CP1_CI_AS + N']' AS file_logical_name ,
  980. CAST(( ( vfs.size_on_disk_bytes / 1024.0 ) / 1024.0 ) AS INT) AS size_on_disk_mb ,
  981. vfs.io_stall_read_ms ,
  982. vfs.num_of_reads ,
  983. vfs.[num_of_bytes_read],
  984. vfs.io_stall_write_ms ,
  985. vfs.num_of_writes ,
  986. vfs.[num_of_bytes_written],
  987. mf.physical_name,
  988. mf.type_desc,
  989. 0,
  990. 0
  991. FROM sys.dm_io_virtual_file_stats (NULL, NULL) AS vfs
  992. INNER JOIN #MasterFiles AS mf ON vfs.file_id = mf.file_id
  993. AND vfs.database_id = mf.database_id
  994. WHERE vfs.num_of_reads > 0
  995. OR vfs.num_of_writes > 0;
  996.  
  997. INSERT INTO #PerfmonStats (Pass, SampleTime, [object_name],[counter_name],[instance_name],[cntr_value],[cntr_type])
  998. SELECT 2 AS Pass,
  999. GETDATE() AS SampleTime,
  1000. RTRIM(dmv.object_name), RTRIM(dmv.counter_name), RTRIM(dmv.instance_name), dmv.cntr_value, dmv.cntr_type
  1001. FROM #PerfmonCounters counters
  1002. INNER JOIN sys.dm_os_performance_counters dmv ON counters.counter_name COLLATE SQL_Latin1_General_CP1_CI_AS = RTRIM(dmv.counter_name) COLLATE SQL_Latin1_General_CP1_CI_AS
  1003. AND counters.[object_name] COLLATE SQL_Latin1_General_CP1_CI_AS = RTRIM(dmv.[object_name]) COLLATE SQL_Latin1_General_CP1_CI_AS
  1004. AND (counters.[instance_name] IS NULL OR counters.[instance_name] COLLATE SQL_Latin1_General_CP1_CI_AS = RTRIM(dmv.[instance_name]) COLLATE SQL_Latin1_General_CP1_CI_AS)
  1005.  
  1006. /* Set the latencies and averages. We could do this with a CTE, but we're not ambitious today. */
  1007. UPDATE fNow
  1008. SET avg_stall_read_ms = ((fNow.io_stall_read_ms - fBase.io_stall_read_ms) / (fNow.num_of_reads - fBase.num_of_reads))
  1009. FROM #FileStats fNow
  1010. 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
  1011. WHERE (fNow.num_of_reads - fBase.num_of_reads) > 0
  1012.  
  1013. UPDATE fNow
  1014. SET avg_stall_write_ms = ((fNow.io_stall_write_ms - fBase.io_stall_write_ms) / (fNow.num_of_writes - fBase.num_of_writes))
  1015. FROM #FileStats fNow
  1016. 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
  1017. WHERE (fNow.num_of_writes - fBase.num_of_writes) > 0
  1018.  
  1019. UPDATE pNow
  1020. SET [value_delta] = pNow.cntr_value - pFirst.cntr_value,
  1021. [value_per_second] = ((1.0 * pNow.cntr_value - pFirst.cntr_value) / DATEDIFF(ss, pFirst.SampleTime, pNow.SampleTime))
  1022. FROM #PerfmonStats pNow
  1023. 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))
  1024. AND pNow.ID > pFirst.ID
  1025. WHERE DATEDIFF(ss, pFirst.SampleTime, pNow.SampleTime) > 0;
  1026.  
  1027.  
  1028. /* If we're within 10 seconds of our projected finish time, do the plan cache analysis. */
  1029. IF DATEDIFF(ss, @FinishSampleTime, GETDATE()) > 10 AND @ExpertMode = 0
  1030. BEGIN
  1031.  
  1032. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
  1033. VALUES (18, 210, 'Query Stats', 'Plan Cache Analysis Skipped', 'http://www.BrentOzar.com/go/topqueries',
  1034. 'Due to excessive load, the plan cache analysis was skipped. To override this, use @ExpertMode = 1.')
  1035.  
  1036. END
  1037. ELSE /* IF DATEDIFF(ss, @FinishSampleTime, GETDATE()) > 10 AND @ExpertMode = 0 */
  1038. BEGIN
  1039.  
  1040.  
  1041. /* Populate #QueryStats. SQL 2005 doesn't have query hash or query plan hash. */
  1042. IF @@VERSION LIKE 'Microsoft SQL Server 2005%'
  1043. 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)
  1044. 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
  1045. FROM sys.dm_exec_query_stats qs
  1046. WHERE qs.last_execution_time >= @StartSampleTimeText;';
  1047. ELSE
  1048. 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)
  1049. 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
  1050. FROM sys.dm_exec_query_stats qs
  1051. WHERE qs.last_execution_time >= @StartSampleTimeText;';
  1052. SET @ParmDefinitions = N'@StartSampleTimeText NVARCHAR(100)';
  1053. SET @Parm1 = CONVERT(NVARCHAR(100), @StartSampleTime, 127);
  1054. EXECUTE sp_executesql @StringToExecute, @ParmDefinitions, @StartSampleTimeText = @Parm1;
  1055.  
  1056. /* Get the totals for the entire plan cache */
  1057. 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)
  1058. 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)
  1059. FROM sys.dm_exec_query_stats qs;
  1060.  
  1061. /*
  1062. Pick the most resource-intensive queries to review. Update the Points field
  1063. in #QueryStats - if a query is in the top 10 for logical reads, CPU time,
  1064. duration, or execution, add 1 to its points.
  1065. */
  1066. WITH qsTop AS (
  1067. SELECT TOP 10 qsNow.ID
  1068. FROM #QueryStats qsNow
  1069. 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
  1070. WHERE qsNow.total_elapsed_time > qsFirst.total_elapsed_time
  1071. AND qsNow.Pass = 2
  1072. AND qsNow.total_elapsed_time - qsFirst.total_elapsed_time > 1000000 /* Only queries with over 1 second of runtime */
  1073. ORDER BY (qsNow.total_elapsed_time - COALESCE(qsFirst.total_elapsed_time, 0)) DESC)
  1074. UPDATE #QueryStats
  1075. SET Points = Points + 1
  1076. FROM #QueryStats qs
  1077. INNER JOIN qsTop ON qs.ID = qsTop.ID;
  1078.  
  1079. WITH qsTop AS (
  1080. SELECT TOP 10 qsNow.ID
  1081. FROM #QueryStats qsNow
  1082. 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
  1083. WHERE qsNow.total_logical_reads > qsFirst.total_logical_reads
  1084. AND qsNow.Pass = 2
  1085. AND qsNow.total_logical_reads - qsFirst.total_logical_reads > 1000 /* Only queries with over 1000 reads */
  1086. ORDER BY (qsNow.total_logical_reads - COALESCE(qsFirst.total_logical_reads, 0)) DESC)
  1087. UPDATE #QueryStats
  1088. SET Points = Points + 1
  1089. FROM #QueryStats qs
  1090. INNER JOIN qsTop ON qs.ID = qsTop.ID;
  1091.  
  1092. WITH qsTop AS (
  1093. SELECT TOP 10 qsNow.ID
  1094. FROM #QueryStats qsNow
  1095. 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
  1096. WHERE qsNow.total_worker_time > qsFirst.total_worker_time
  1097. AND qsNow.Pass = 2
  1098. AND qsNow.total_worker_time - qsFirst.total_worker_time > 1000000 /* Only queries with over 1 second of worker time */
  1099. ORDER BY (qsNow.total_worker_time - COALESCE(qsFirst.total_worker_time, 0)) DESC)
  1100. UPDATE #QueryStats
  1101. SET Points = Points + 1
  1102. FROM #QueryStats qs
  1103. INNER JOIN qsTop ON qs.ID = qsTop.ID;
  1104.  
  1105. WITH qsTop AS (
  1106. SELECT TOP 10 qsNow.ID
  1107. FROM #QueryStats qsNow
  1108. 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
  1109. WHERE qsNow.execution_count > qsFirst.execution_count
  1110. AND qsNow.Pass = 2
  1111. AND (qsNow.total_elapsed_time - qsFirst.total_elapsed_time > 1000000 /* Only queries with over 1 second of runtime */
  1112. OR qsNow.total_logical_reads - qsFirst.total_logical_reads > 1000 /* Only queries with over 1000 reads */
  1113. OR qsNow.total_worker_time - qsFirst.total_worker_time > 1000000 /* Only queries with over 1 second of worker time */)
  1114. ORDER BY (qsNow.execution_count - COALESCE(qsFirst.execution_count, 0)) DESC)
  1115. UPDATE #QueryStats
  1116. SET Points = Points + 1
  1117. FROM #QueryStats qs
  1118. INNER JOIN qsTop ON qs.ID = qsTop.ID;
  1119.  
  1120. /* Query Stats - CheckID 17 - Most Resource-Intensive Queries */
  1121. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, QueryStatsNowID, QueryStatsFirstID, PlanHandle)
  1122. SELECT 17, 210, 'Query Stats', 'Most Resource-Intensive Queries', 'http://www.BrentOzar.com/go/topqueries',
  1123. 'Query stats during the sample:' + @LineFeed +
  1124. 'Executions: ' + CAST(qsNow.execution_count - (COALESCE(qsFirst.execution_count, 0)) AS NVARCHAR(100)) + @LineFeed +
  1125. 'Elapsed Time: ' + CAST(qsNow.total_elapsed_time - (COALESCE(qsFirst.total_elapsed_time, 0)) AS NVARCHAR(100)) + @LineFeed +
  1126. 'CPU Time: ' + CAST(qsNow.total_worker_time - (COALESCE(qsFirst.total_worker_time, 0)) AS NVARCHAR(100)) + @LineFeed +
  1127. 'Logical Reads: ' + CAST(qsNow.total_logical_reads - (COALESCE(qsFirst.total_logical_reads, 0)) AS NVARCHAR(100)) + @LineFeed +
  1128. 'Logical Writes: ' + CAST(qsNow.total_logical_writes - (COALESCE(qsFirst.total_logical_writes, 0)) AS NVARCHAR(100)) + @LineFeed +
  1129. 'CLR Time: ' + CAST(qsNow.total_clr_time - (COALESCE(qsFirst.total_clr_time, 0)) AS NVARCHAR(100)) + @LineFeed +
  1130. @LineFeed + @LineFeed + 'Query stats since ' + CONVERT(NVARCHAR(100), qsNow.creation_time ,121) + @LineFeed +
  1131. 'Executions: ' + CAST(qsNow.execution_count AS NVARCHAR(100)) +
  1132. 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 +
  1133. 'Elapsed Time: ' + CAST(qsNow.total_elapsed_time AS NVARCHAR(100)) +
  1134. 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 +
  1135. 'CPU Time: ' + CAST(qsNow.total_worker_time AS NVARCHAR(100)) +
  1136. 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 +
  1137. 'Logical Reads: ' + CAST(qsNow.total_logical_reads AS NVARCHAR(100)) +
  1138. 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 +
  1139. 'Logical Writes: ' + CAST(qsNow.total_logical_writes AS NVARCHAR(100)) +
  1140. 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 +
  1141. 'CLR Time: ' + CAST(qsNow.total_clr_time AS NVARCHAR(100)) +
  1142. 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 +
  1143. --@LineFeed + @LineFeed + 'Query hash: ' + CAST(qsNow.query_hash AS NVARCHAR(100)) + @LineFeed +
  1144. --@LineFeed + @LineFeed + 'Query plan hash: ' + CAST(qsNow.query_plan_hash AS NVARCHAR(100)) +
  1145. @LineFeed AS Details,
  1146. 'See the URL for tuning tips on why this query may be consuming resources.' AS HowToStopIt,
  1147. qp.query_plan,
  1148. QueryText = SUBSTRING(st.text,
  1149. (qsNow.statement_start_offset / 2) + 1,
  1150. ((CASE qsNow.statement_end_offset
  1151. WHEN -1 THEN DATALENGTH(st.text)
  1152. ELSE qsNow.statement_end_offset
  1153. END - qsNow.statement_start_offset) / 2) + 1),
  1154. qsNow.ID AS QueryStatsNowID,
  1155. qsFirst.ID AS QueryStatsFirstID,
  1156. qsNow.plan_handle AS PlanHandle
  1157. FROM #QueryStats qsNow
  1158. INNER JOIN #QueryStats qsTotal ON qsTotal.Pass = 0
  1159. 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
  1160. CROSS APPLY sys.dm_exec_sql_text(qsNow.sql_handle) AS st
  1161. CROSS APPLY sys.dm_exec_query_plan(qsNow.plan_handle) AS qp
  1162. WHERE qsNow.Points > 0 AND st.text IS NOT NULL AND qp.query_plan IS NOT NULL
  1163.  
  1164. UPDATE #AskBrentResults
  1165. SET DatabaseID = CAST(attr.value AS INT),
  1166. DatabaseName = DB_NAME(CAST(attr.value AS INT))
  1167. FROM #AskBrentResults
  1168. CROSS APPLY sys.dm_exec_plan_attributes(#AskBrentResults.PlanHandle) AS attr
  1169. WHERE attr.attribute = 'dbid'
  1170.  
  1171.  
  1172. END /* IF DATEDIFF(ss, @FinishSampleTime, GETDATE()) > 10 AND @ExpertMode = 0 */
  1173.  
  1174.  
  1175. /* Wait Stats - CheckID 6 */
  1176. /* Compare the current wait stats to the sample we took at the start, and insert the top 10 waits. */
  1177. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, DetailsInt)
  1178. SELECT TOP 10 6 AS CheckID,
  1179. 200 AS Priority,
  1180. 'Wait Stats' AS FindingGroup,
  1181. wNow.wait_type AS Finding,
  1182. N'http://www.brentozar.com/sql/wait-stats/#' + wNow.wait_type AS URL,
  1183. 'For ' + CAST(((wNow.wait_time_ms - COALESCE(wBase.wait_time_ms,0)) / 1000) AS NVARCHAR(100)) + ' seconds over the last ' + CASE @Seconds WHEN 0 THEN (CAST(DATEDIFF(dd,@StartSampleTime,@FinishSampleTime) AS NVARCHAR(10)) + ' days') ELSE (CAST(@Seconds AS NVARCHAR(10)) + ' seconds') END + ', SQL Server was waiting on this particular bottleneck.' + @LineFeed + @LineFeed AS Details,
  1184. 'See the URL for more details on how to mitigate this wait type.' AS HowToStopIt,
  1185. ((wNow.wait_time_ms - COALESCE(wBase.wait_time_ms,0)) / 1000) AS DetailsInt
  1186. FROM #WaitStats wNow
  1187. LEFT OUTER JOIN #WaitStats wBase ON wNow.wait_type = wBase.wait_type AND wNow.SampleTime > wBase.SampleTime
  1188. WHERE wNow.wait_time_ms > (wBase.wait_time_ms + (.5 * (DATEDIFF(ss,@StartSampleTime,@FinishSampleTime)) * 1000)) /* Only look for things we've actually waited on for half of the time or more */
  1189. ORDER BY (wNow.wait_time_ms - COALESCE(wBase.wait_time_ms,0)) DESC;
  1190.  
  1191. /* Server Performance - Slow Data File Reads - CheckID 11 */
  1192. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, DatabaseID, DatabaseName)
  1193. SELECT TOP 10 11 AS CheckID,
  1194. 50 AS Priority,
  1195. 'Server Performance' AS FindingGroup,
  1196. 'Slow Data File Reads' AS Finding,
  1197. 'http://www.BrentOzar.com/go/slow/' AS URL,
  1198. 'File: ' + fNow.PhysicalName + @LineFeed
  1199. + 'Number of reads during the sample: ' + CAST((fNow.num_of_reads - fBase.num_of_reads) AS NVARCHAR(20)) + @LineFeed
  1200. + '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
  1201. + '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
  1202. + 'Microsoft guidance for data file read speed: 20ms or less.' + @LineFeed + @LineFeed AS Details,
  1203. 'See the URL for more details on how to mitigate this wait type.' AS HowToStopIt,
  1204. fNow.DatabaseID,
  1205. fNow.DatabaseName
  1206. FROM #FileStats fNow
  1207. 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)
  1208. WHERE (fNow.io_stall_read_ms - fBase.io_stall_read_ms) / (fNow.num_of_reads - fBase.num_of_reads) >= @FileLatencyThresholdMS
  1209. AND fNow.TypeDesc = 'ROWS'
  1210. ORDER BY (fNow.io_stall_read_ms - fBase.io_stall_read_ms) / (fNow.num_of_reads - fBase.num_of_reads) DESC;
  1211.  
  1212. /* Server Performance - Slow Log File Writes - CheckID 12 */
  1213. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, DatabaseID, DatabaseName)
  1214. SELECT TOP 10 12 AS CheckID,
  1215. 50 AS Priority,
  1216. 'Server Performance' AS FindingGroup,
  1217. 'Slow Log File Writes' AS Finding,
  1218. 'http://www.BrentOzar.com/go/slow/' AS URL,
  1219. 'File: ' + fNow.PhysicalName + @LineFeed
  1220. + 'Number of writes during the sample: ' + CAST((fNow.num_of_writes - fBase.num_of_writes) AS NVARCHAR(20)) + @LineFeed
  1221. + '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
  1222. + '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
  1223. + 'Microsoft guidance for log file write speed: 3ms or less.' + @LineFeed + @LineFeed AS Details,
  1224. 'See the URL for more details on how to mitigate this wait type.' AS HowToStopIt,
  1225. fNow.DatabaseID,
  1226. fNow.DatabaseName
  1227. FROM #FileStats fNow
  1228. 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)
  1229. WHERE (fNow.io_stall_write_ms - fBase.io_stall_write_ms) / (fNow.num_of_writes - fBase.num_of_writes) >= @FileLatencyThresholdMS
  1230. AND fNow.TypeDesc = 'LOG'
  1231. ORDER BY (fNow.io_stall_write_ms - fBase.io_stall_write_ms) / (fNow.num_of_writes - fBase.num_of_writes) DESC;
  1232.  
  1233.  
  1234. /* SQL Server Internal Maintenance - Log File Growing - CheckID 13 */
  1235. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
  1236. SELECT 13 AS CheckID,
  1237. 1 AS Priority,
  1238. 'SQL Server Internal Maintenance' AS FindingGroup,
  1239. 'Log File Growing' AS Finding,
  1240. 'http://www.BrentOzar.com/askbrent/file-growing/' AS URL,
  1241. 'Number of growths during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
  1242. + 'Determined by sampling Perfmon counter ' + ps.object_name + ' - ' + ps.counter_name + @LineFeed AS Details,
  1243. '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
  1244. FROM #PerfmonStats ps
  1245. WHERE ps.Pass = 2
  1246. AND object_name = @ServiceName + ':Databases'
  1247. AND counter_name = 'Log Growths'
  1248. AND value_delta > 0
  1249.  
  1250.  
  1251. /* SQL Server Internal Maintenance - Log File Shrinking - CheckID 14 */
  1252. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
  1253. SELECT 14 AS CheckID,
  1254. 1 AS Priority,
  1255. 'SQL Server Internal Maintenance' AS FindingGroup,
  1256. 'Log File Shrinking' AS Finding,
  1257. 'http://www.BrentOzar.com/askbrent/file-shrinking/' AS URL,
  1258. 'Number of shrinks during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
  1259. + 'Determined by sampling Perfmon counter ' + ps.object_name + ' - ' + ps.counter_name + @LineFeed AS Details,
  1260. '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
  1261. FROM #PerfmonStats ps
  1262. WHERE ps.Pass = 2
  1263. AND object_name = @ServiceName + ':Databases'
  1264. AND counter_name = 'Log Shrinks'
  1265. AND value_delta > 0
  1266.  
  1267. /* Query Problems - Compilations/Sec High - CheckID 15 */
  1268. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
  1269. SELECT 15 AS CheckID,
  1270. 50 AS Priority,
  1271. 'Query Problems' AS FindingGroup,
  1272. 'Compilations/Sec High' AS Finding,
  1273. 'http://www.BrentOzar.com/askbrent/compilations/' AS URL,
  1274. 'Number of batch requests during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
  1275. + 'Number of compilations during the sample: ' + CAST(psComp.value_delta AS NVARCHAR(20)) + @LineFeed
  1276. + '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,
  1277. 'Find out why plans are not being reused, and consider enabling Forced Parameterization. See the URL for more details.' AS HowToStopIt
  1278. FROM #PerfmonStats ps
  1279. INNER JOIN #PerfmonStats psComp ON psComp.Pass = 2 AND psComp.object_name = @ServiceName + ':SQL Statistics' AND psComp.counter_name = 'SQL Compilations/sec' AND psComp.value_delta > 0
  1280. WHERE ps.Pass = 2
  1281. AND ps.object_name = @ServiceName + ':SQL Statistics'
  1282. AND ps.counter_name = 'Batch Requests/sec'
  1283. AND ps.value_delta > (1000 * @Seconds) /* Ignore servers sitting idle */
  1284. AND (psComp.value_delta * 10) > ps.value_delta /* Compilations are more than 10% of batch requests per second */
  1285.  
  1286. /* Query Problems - Re-Compilations/Sec High - CheckID 16 */
  1287. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
  1288. SELECT 16 AS CheckID,
  1289. 50 AS Priority,
  1290. 'Query Problems' AS FindingGroup,
  1291. 'Re-Compilations/Sec High' AS Finding,
  1292. 'http://www.BrentOzar.com/askbrent/recompilations/' AS URL,
  1293. 'Number of batch requests during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
  1294. + 'Number of recompilations during the sample: ' + CAST(psComp.value_delta AS NVARCHAR(20)) + @LineFeed
  1295. + 'More than 10% of our queries are being recompiled. This is typically due to statistics changing on objects.' + @LineFeed AS Details,
  1296. 'Find out which objects are changing so quickly that they hit the stats update threshold. See the URL for more details.' AS HowToStopIt
  1297. FROM #PerfmonStats ps
  1298. INNER JOIN #PerfmonStats psComp ON psComp.Pass = 2 AND psComp.object_name = @ServiceName + ':SQL Statistics' AND psComp.counter_name = 'SQL Re-Compilations/sec' AND psComp.value_delta > 0
  1299. WHERE ps.Pass = 2
  1300. AND ps.object_name = @ServiceName + ':SQL Statistics'
  1301. AND ps.counter_name = 'Batch Requests/sec'
  1302. AND ps.value_delta > (1000 * @Seconds) /* Ignore servers sitting idle */
  1303. AND (psComp.value_delta * 10) > ps.value_delta /* Recompilations are more than 10% of batch requests per second */
  1304.  
  1305. /* Server Info - Batch Requests per Sec - CheckID 19 */
  1306. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, DetailsInt)
  1307. SELECT 19 AS CheckID,
  1308. 250 AS Priority,
  1309. 'Server Info' AS FindingGroup,
  1310. 'Batch Requests per Sec' AS Finding,
  1311. 'http://www.BrentOzar.com/go/measure' AS URL,
  1312. CAST(ps.value_delta / (DATEDIFF(ss, ps1.SampleTime, ps.SampleTime)) AS NVARCHAR(20)) AS Details,
  1313. ps.value_delta / (DATEDIFF(ss, ps1.SampleTime, ps.SampleTime)) AS DetailsInt
  1314. FROM #PerfmonStats ps
  1315. INNER JOIN #PerfmonStats ps1 ON ps.object_name = ps1.object_name AND ps.counter_name = ps1.counter_name AND ps1.Pass = 1
  1316. WHERE ps.Pass = 2
  1317. AND ps.object_name = @ServiceName + ':SQL Statistics'
  1318. AND ps.counter_name = 'Batch Requests/sec';
  1319.  
  1320.  
  1321. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','SQL Compilations/sec', NULL)
  1322. INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES (@ServiceName + ':SQL Statistics','SQL Re-Compilations/sec', NULL)
  1323.  
  1324. /* Server Info - SQL Compilations/sec - CheckID 25 */
  1325. IF @ExpertMode = 1
  1326. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, DetailsInt)
  1327. SELECT 25 AS CheckID,
  1328. 250 AS Priority,
  1329. 'Server Info' AS FindingGroup,
  1330. 'SQL Compilations per Sec' AS Finding,
  1331. 'http://www.BrentOzar.com/go/measure' AS URL,
  1332. CAST(ps.value_delta / (DATEDIFF(ss, ps1.SampleTime, ps.SampleTime)) AS NVARCHAR(20)) AS Details,
  1333. ps.value_delta / (DATEDIFF(ss, ps1.SampleTime, ps.SampleTime)) AS DetailsInt
  1334. FROM #PerfmonStats ps
  1335. INNER JOIN #PerfmonStats ps1 ON ps.object_name = ps1.object_name AND ps.counter_name = ps1.counter_name AND ps1.Pass = 1
  1336. WHERE ps.Pass = 2
  1337. AND ps.object_name = @ServiceName + ':SQL Statistics'
  1338. AND ps.counter_name = 'SQL Compilations/sec';
  1339.  
  1340. /* Server Info - SQL Re-Compilations/sec - CheckID 26 */
  1341. IF @ExpertMode = 1
  1342. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, DetailsInt)
  1343. SELECT 26 AS CheckID,
  1344. 250 AS Priority,
  1345. 'Server Info' AS FindingGroup,
  1346. 'SQL Re-Compilations per Sec' AS Finding,
  1347. 'http://www.BrentOzar.com/go/measure' AS URL,
  1348. CAST(ps.value_delta / (DATEDIFF(ss, ps1.SampleTime, ps.SampleTime)) AS NVARCHAR(20)) AS Details,
  1349. ps.value_delta / (DATEDIFF(ss, ps1.SampleTime, ps.SampleTime)) AS DetailsInt
  1350. FROM #PerfmonStats ps
  1351. INNER JOIN #PerfmonStats ps1 ON ps.object_name = ps1.object_name AND ps.counter_name = ps1.counter_name AND ps1.Pass = 1
  1352. WHERE ps.Pass = 2
  1353. AND ps.object_name = @ServiceName + ':SQL Statistics'
  1354. AND ps.counter_name = 'SQL Re-Compilations/sec';
  1355.  
  1356. /* Server Info - Wait Time per Core per Sec - CheckID 20 */
  1357. IF @Seconds > 0
  1358. BEGIN
  1359. WITH waits1(SampleTime, waits_ms) AS (SELECT SampleTime, SUM(ws1.wait_time_ms) FROM #WaitStats ws1 WHERE ws1.Pass = 1 GROUP BY SampleTime),
  1360. waits2(SampleTime, waits_ms) AS (SELECT SampleTime, SUM(ws2.wait_time_ms) FROM #WaitStats ws2 WHERE ws2.Pass = 2 GROUP BY SampleTime),
  1361. cores(cpu_count) AS (SELECT SUM(1) FROM sys.dm_os_schedulers WHERE status = 'VISIBLE ONLINE' AND is_online = 1)
  1362. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, DetailsInt)
  1363. SELECT 19 AS CheckID,
  1364. 250 AS Priority,
  1365. 'Server Info' AS FindingGroup,
  1366. 'Wait Time per Core per Sec' AS Finding,
  1367. 'http://www.BrentOzar.com/go/measure' AS URL,
  1368. CAST((waits2.waits_ms - waits1.waits_ms) / 1000 / i.cpu_count / DATEDIFF(ss, waits1.SampleTime, waits2.SampleTime) AS NVARCHAR(20)) AS Details,
  1369. (waits2.waits_ms - waits1.waits_ms) / 1000 / i.cpu_count / DATEDIFF(ss, waits1.SampleTime, waits2.SampleTime) AS DetailsInt
  1370. FROM cores i
  1371. CROSS JOIN waits1
  1372. CROSS JOIN waits2;
  1373. END
  1374.  
  1375. /* Server Performance - High CPU Utilization CheckID 24 */
  1376. IF @Seconds >= 30
  1377. BEGIN
  1378. /* If we're waiting 30+ seconds, run this check at the end.
  1379. We get this data from the ring buffers, and it's only updated once per minute, so might
  1380. as well get it now - whereas if we're checking 30+ seconds, it might get updated by the
  1381. end of our sp_AskBrent session. */
  1382. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, Details, DetailsInt, URL)
  1383. SELECT 24, 50, 'Server Performance', 'High CPU Utilization', CAST(100 - SystemIdle AS NVARCHAR(20)) + N'%. Ring buffer details: ' + CAST(record AS NVARCHAR(4000)), 100 - SystemIdle, 'http://www.BrentOzar.com/go/cpu'
  1384. FROM (
  1385. SELECT record,
  1386. record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int') as SystemIdle
  1387. FROM (
  1388. SELECT TOP 1 CONVERT(XML, record) as record
  1389. FROM sys.dm_os_ring_buffers
  1390. WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
  1391. AND record LIKE '%<SystemHealth>%'
  1392. ORDER BY timestamp DESC) AS rb
  1393. ) as y
  1394. WHERE 100 - SystemIdle >= 50
  1395.  
  1396. INSERT INTO #AskBrentResults (CheckID, Priority, FindingsGroup, Finding, Details, DetailsInt, URL)
  1397. SELECT 23, 250, 'Server Info', 'CPU Utilization', CAST(100 - SystemIdle AS NVARCHAR(20)) + N'%. Ring buffer details: ' + CAST(record AS NVARCHAR(4000)), 100 - SystemIdle, 'http://www.BrentOzar.com/go/cpu'
  1398. FROM (
  1399. SELECT record,
  1400. record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int') as SystemIdle
  1401. FROM (
  1402. SELECT TOP 1 CONVERT(XML, record) as record
  1403. FROM sys.dm_os_ring_buffers
  1404. WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
  1405. AND record LIKE '%<SystemHealth>%'
  1406. ORDER BY timestamp DESC) AS rb
  1407. ) as y
  1408.  
  1409. END /* IF @Seconds < 30 */
  1410.  
  1411.  
  1412. /* If we didn't find anything, apologize. */
  1413. IF NOT EXISTS (SELECT * FROM #AskBrentResults WHERE Priority < 250)
  1414. BEGIN
  1415.  
  1416. INSERT INTO #AskBrentResults
  1417. ( CheckID ,
  1418. Priority ,
  1419. FindingsGroup ,
  1420. Finding ,
  1421. URL ,
  1422. Details
  1423. )
  1424. VALUES ( -1 ,
  1425. 1 ,
  1426. 'No Problems Found' ,
  1427. 'From Brent Ozar Unlimited' ,
  1428. 'http://www.BrentOzar.com/askbrent/' ,
  1429. 'Try running our more in-depth checks: http://www.BrentOzar.com/blitz/' + @LineFeed + 'or there may not be an unusual SQL Server performance problem. '
  1430. );
  1431.  
  1432. END /*IF NOT EXISTS (SELECT * FROM #AskBrentResults) */
  1433.  
  1434. /* Add credits for the nice folks who put so much time into building and maintaining this for free: */
  1435. INSERT INTO #AskBrentResults
  1436. ( CheckID ,
  1437. Priority ,
  1438. FindingsGroup ,
  1439. Finding ,
  1440. URL ,
  1441. Details
  1442. )
  1443. VALUES ( -1 ,
  1444. 255 ,
  1445. 'Thanks!' ,
  1446. 'From Brent Ozar Unlimited' ,
  1447. 'http://www.BrentOzar.com/askbrent/' ,
  1448. '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 [email protected]. '
  1449. );
  1450.  
  1451. INSERT INTO #AskBrentResults
  1452. ( CheckID ,
  1453. Priority ,
  1454. FindingsGroup ,
  1455. Finding ,
  1456. URL ,
  1457. Details
  1458.  
  1459. )
  1460. VALUES ( -1 ,
  1461. 0 ,
  1462. 'sp_AskBrent (TM) v' + CAST(@Version AS VARCHAR(20)) + ' as of ' + CAST(CONVERT(DATETIME, @VersionDate, 102) AS VARCHAR(100)),
  1463. 'From Brent Ozar Unlimited' ,
  1464. 'http://www.BrentOzar.com/askbrent/' ,
  1465. '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 [email protected].'
  1466. );
  1467.  
  1468. /* Outdated sp_Blitz - sp_Blitz is Over 6 Months Old */
  1469. IF DATEDIFF(MM, @VersionDate, GETDATE()) > 6
  1470. BEGIN
  1471. INSERT INTO #AskBrentResults
  1472. ( CheckID ,
  1473. Priority ,
  1474. FindingsGroup ,
  1475. Finding ,
  1476. URL ,
  1477. Details
  1478. )
  1479. SELECT 27 AS CheckID ,
  1480. 0 AS Priority ,
  1481. 'Outdated sp_AskBrent' AS FindingsGroup ,
  1482. 'sp_AskBrent is Over 6 Months Old' AS Finding ,
  1483. 'http://www.BrentOzar.com/askbrent/' AS URL ,
  1484. 'Some things get better with age, like fine wine and your T-SQL. However, sp_AskBrent is not one of those things - time to go download the current one.' AS Details
  1485. END
  1486.  
  1487.  
  1488.  
  1489. /* @OutputTableName lets us export the results to a permanent table */
  1490. IF @OutputDatabaseName IS NOT NULL
  1491. AND @OutputSchemaName IS NOT NULL
  1492. AND @OutputTableName IS NOT NULL
  1493. AND @OutputTableName NOT LIKE '#%'
  1494. AND EXISTS ( SELECT *
  1495. FROM sys.databases
  1496. WHERE QUOTENAME([name]) = @OutputDatabaseName)
  1497. BEGIN
  1498. SET @StringToExecute = 'USE '
  1499. + @OutputDatabaseName
  1500. + '; IF EXISTS(SELECT * FROM '
  1501. + @OutputDatabaseName
  1502. + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
  1503. + @OutputSchemaName
  1504. + ''') AND NOT EXISTS (SELECT * FROM '
  1505. + @OutputDatabaseName
  1506. + '.INFORMATION_SCHEMA.TABLES WHERE QUOTENAME(TABLE_SCHEMA) = '''
  1507. + @OutputSchemaName + ''' AND QUOTENAME(TABLE_NAME) = '''
  1508. + @OutputTableName + ''') CREATE TABLE '
  1509. + @OutputSchemaName + '.'
  1510. + @OutputTableName
  1511. + ' (ID INT IDENTITY(1,1) NOT NULL,
  1512. ServerName NVARCHAR(128),
  1513. CheckDate DATETIME,
  1514. AskBrentVersion INT,
  1515. CheckID INT NOT NULL,
  1516. Priority TINYINT NOT NULL,
  1517. FindingsGroup VARCHAR(50) NOT NULL,
  1518. Finding VARCHAR(200) NOT NULL,
  1519. URL VARCHAR(200) NOT NULL,
  1520. Details NVARCHAR(4000) NULL,
  1521. HowToStopIt [XML] NULL,
  1522. QueryPlan [XML] NULL,
  1523. QueryText NVARCHAR(MAX) NULL,
  1524. StartTime DATETIME NULL,
  1525. LoginName NVARCHAR(128) NULL,
  1526. NTUserName NVARCHAR(128) NULL,
  1527. OriginalLoginName NVARCHAR(128) NULL,
  1528. ProgramName NVARCHAR(128) NULL,
  1529. HostName NVARCHAR(128) NULL,
  1530. DatabaseID INT NULL,
  1531. DatabaseName NVARCHAR(128) NULL,
  1532. OpenTransactionCount INT NULL,
  1533. DetailsInt INT NULL,
  1534. CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
  1535.  
  1536. EXEC(@StringToExecute);
  1537. SET @StringToExecute = N' IF EXISTS(SELECT * FROM '
  1538. + @OutputDatabaseName
  1539. + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
  1540. + @OutputSchemaName + ''') INSERT '
  1541. + @OutputDatabaseName + '.'
  1542. + @OutputSchemaName + '.'
  1543. + @OutputTableName
  1544. + ' (ServerName, CheckDate, AskBrentVersion, CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount, DetailsInt) SELECT '''
  1545. + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
  1546. + ''', ''' + (CONVERT(NVARCHAR(100), @StartSampleTime, 127)) + ''', ' + CAST(@Version AS NVARCHAR(128))
  1547. + ', CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount, DetailsInt FROM #AskBrentResults ORDER BY Priority , FindingsGroup , Finding , Details';
  1548. EXEC(@StringToExecute);
  1549. END
  1550. ELSE IF (SUBSTRING(@OutputTableName, 2, 2) = '##')
  1551. BEGIN
  1552. SET @StringToExecute = N' IF (OBJECT_ID(''tempdb..'
  1553. + @OutputTableName
  1554. + ''') IS NULL) CREATE TABLE '
  1555. + @OutputTableName
  1556. + ' (ID INT IDENTITY(1,1) NOT NULL,
  1557. ServerName NVARCHAR(128),
  1558. CheckDate DATETIME,
  1559. AskBrentVersion INT,
  1560. CheckID INT NOT NULL,
  1561. Priority TINYINT NOT NULL,
  1562. FindingsGroup VARCHAR(50) NOT NULL,
  1563. Finding VARCHAR(200) NOT NULL,
  1564. URL VARCHAR(200) NOT NULL,
  1565. Details NVARCHAR(4000) NULL,
  1566. HowToStopIt [XML] NULL,
  1567. QueryPlan [XML] NULL,
  1568. QueryText NVARCHAR(MAX) NULL,
  1569. StartTime DATETIME NULL,
  1570. LoginName NVARCHAR(128) NULL,
  1571. NTUserName NVARCHAR(128) NULL,
  1572. OriginalLoginName NVARCHAR(128) NULL,
  1573. ProgramName NVARCHAR(128) NULL,
  1574. HostName NVARCHAR(128) NULL,
  1575. DatabaseID INT NULL,
  1576. DatabaseName NVARCHAR(128) NULL,
  1577. OpenTransactionCount INT NULL,
  1578. DetailsInt INT NULL,
  1579. CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
  1580. + ' INSERT '
  1581. + @OutputTableName
  1582. + ' (ServerName, CheckDate, AskBrentVersion, CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount, DetailsInt) SELECT '''
  1583. + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
  1584. + ''', ''' + CONVERT(NVARCHAR(100), @StartSampleTime, 127) + ''', ' + CAST(@Version AS NVARCHAR(128))
  1585. + ', CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount, DetailsInt FROM #AskBrentResults ORDER BY Priority , FindingsGroup , Finding , Details';
  1586. EXEC(@StringToExecute);
  1587. END
  1588. ELSE IF (SUBSTRING(@OutputTableName, 2, 1) = '#')
  1589. BEGIN
  1590. RAISERROR('Due to the nature of Dymamic SQL, only global (i.e. double pound (##)) temp tables are supported for @OutputTableName', 16, 0)
  1591. END
  1592.  
  1593. /* @OutputTableNameFileStats lets us export the results to a permanent table */
  1594. IF @OutputDatabaseName IS NOT NULL
  1595. AND @OutputSchemaName IS NOT NULL
  1596. AND @OutputTableNameFileStats IS NOT NULL
  1597. AND @OutputTableNameFileStats NOT LIKE '#%'
  1598. AND EXISTS ( SELECT *
  1599. FROM sys.databases
  1600. WHERE QUOTENAME([name]) = @OutputDatabaseName)
  1601. BEGIN
  1602. /* Create the table */
  1603. SET @StringToExecute = 'USE '
  1604. + @OutputDatabaseName
  1605. + '; IF EXISTS(SELECT * FROM '
  1606. + @OutputDatabaseName
  1607. + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
  1608. + @OutputSchemaName
  1609. + ''') AND NOT EXISTS (SELECT * FROM '
  1610. + @OutputDatabaseName
  1611. + '.INFORMATION_SCHEMA.TABLES WHERE QUOTENAME(TABLE_SCHEMA) = '''
  1612. + @OutputSchemaName + ''' AND QUOTENAME(TABLE_NAME) = '''
  1613. + @OutputTableNameFileStats + ''') CREATE TABLE '
  1614. + @OutputSchemaName + '.'
  1615. + @OutputTableNameFileStats
  1616. + ' (ID INT IDENTITY(1,1) NOT NULL,
  1617. ServerName NVARCHAR(128),
  1618. CheckDate DATETIME,
  1619. DatabaseID INT NOT NULL,
  1620. FileID INT NOT NULL,
  1621. DatabaseName NVARCHAR(256) ,
  1622. FileLogicalName NVARCHAR(256) ,
  1623. TypeDesc NVARCHAR(60) ,
  1624. SizeOnDiskMB BIGINT ,
  1625. io_stall_read_ms BIGINT ,
  1626. num_of_reads BIGINT ,
  1627. bytes_read BIGINT ,
  1628. io_stall_write_ms BIGINT ,
  1629. num_of_writes BIGINT ,
  1630. bytes_written BIGINT,
  1631. PhysicalName NVARCHAR(520) ,
  1632. CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
  1633. EXEC(@StringToExecute);
  1634.  
  1635. /* Create the view */
  1636. SET @ObjectFullName = @OutputDatabaseName + N'.' + @OutputSchemaName + N'.' + @OutputTableNameFileStats_View;
  1637. IF OBJECT_ID(@ObjectFullName) IS NULL
  1638. BEGIN
  1639. SET @StringToExecute = 'USE '
  1640. + @OutputDatabaseName
  1641. + '; EXEC (''CREATE VIEW '
  1642. + @OutputSchemaName + '.'
  1643. + @OutputTableNameFileStats_View + ' AS ' + @LineFeed
  1644. + 'SELECT f.ServerName, f.CheckDate, f.DatabaseID, f.DatabaseName, f.FileID, f.FileLogicalName, f.TypeDesc, f.PhysicalName, f.SizeOnDiskMB' + @LineFeed
  1645. + ', DATEDIFF(ss, fPrior.CheckDate, f.CheckDate) AS ElapsedSeconds' + @LineFeed
  1646. + ', (f.SizeOnDiskMB - fPrior.SizeOnDiskMB) AS SizeOnDiskMBgrowth' + @LineFeed
  1647. + ', (f.io_stall_read_ms - fPrior.io_stall_read_ms) AS io_stall_read_ms' + @LineFeed
  1648. + ', io_stall_read_ms_average = CASE WHEN (f.num_of_reads - fPrior.num_of_reads) = 0 THEN 0 ELSE (f.io_stall_read_ms - fPrior.io_stall_read_ms) / (f.num_of_reads - fPrior.num_of_reads) END' + @LineFeed
  1649. + ', (f.num_of_reads - fPrior.num_of_reads) AS num_of_reads' + @LineFeed
  1650. + ', (f.bytes_read - fPrior.bytes_read) / 1024.0 / 1024.0 AS megabytes_read' + @LineFeed
  1651. + ', (f.io_stall_write_ms - fPrior.io_stall_write_ms) AS io_stall_write_ms' + @LineFeed
  1652. + ', io_stall_write_ms_average = CASE WHEN (f.num_of_writes - fPrior.num_of_writes) = 0 THEN 0 ELSE (f.io_stall_write_ms - fPrior.io_stall_write_ms) / (f.num_of_writes - fPrior.num_of_writes) END' + @LineFeed
  1653. + ', (f.num_of_writes - fPrior.num_of_writes) AS num_of_writes' + @LineFeed
  1654. + ', (f.bytes_written - fPrior.bytes_written) / 1024.0 / 1024.0 AS megabytes_written' + @LineFeed
  1655. + 'FROM ' + @OutputSchemaName + '.' + @OutputTableNameFileStats + ' f' + @LineFeed
  1656. + 'INNER JOIN ' + @OutputSchemaName + '.' + @OutputTableNameFileStats + ' fPrior ON f.ServerName = fPrior.ServerName AND f.DatabaseID = fPrior.DatabaseID AND f.FileID = fPrior.FileID AND f.CheckDate > fPrior.CheckDate' + @LineFeed
  1657. + 'LEFT OUTER JOIN ' + @OutputSchemaName + '.' + @OutputTableNameFileStats + ' fMiddle ON f.ServerName = fMiddle.ServerName AND f.DatabaseID = fMiddle.DatabaseID AND f.FileID = fMiddle.FileID AND f.CheckDate > fMiddle.CheckDate AND fMiddle.CheckDate > fPrior.CheckDate' + @LineFeed
  1658. + 'WHERE fMiddle.ID IS NULL;'')'
  1659. EXEC(@StringToExecute);
  1660. END
  1661.  
  1662. SET @StringToExecute = N' IF EXISTS(SELECT * FROM '
  1663. + @OutputDatabaseName
  1664. + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
  1665. + @OutputSchemaName + ''') INSERT '
  1666. + @OutputDatabaseName + '.'
  1667. + @OutputSchemaName + '.'
  1668. + @OutputTableNameFileStats
  1669. + ' (ServerName, CheckDate, DatabaseID, FileID, DatabaseName, FileLogicalName, TypeDesc, SizeOnDiskMB, io_stall_read_ms, num_of_reads, bytes_read, io_stall_write_ms, num_of_writes, bytes_written, PhysicalName) SELECT '''
  1670. + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
  1671. + ''', ''' + CONVERT(NVARCHAR(100), @StartSampleTime, 127) + ''', '
  1672. + 'DatabaseID, FileID, DatabaseName, FileLogicalName, TypeDesc, SizeOnDiskMB, io_stall_read_ms, num_of_reads, bytes_read, io_stall_write_ms, num_of_writes, bytes_written, PhysicalName FROM #FileStats WHERE Pass = 2';
  1673. EXEC(@StringToExecute);
  1674. END
  1675. ELSE IF (SUBSTRING(@OutputTableNameFileStats, 2, 2) = '##')
  1676. BEGIN
  1677. SET @StringToExecute = N' IF (OBJECT_ID(''tempdb..'
  1678. + @OutputTableNameFileStats
  1679. + ''') IS NULL) CREATE TABLE '
  1680. + @OutputTableNameFileStats
  1681. + ' (ID INT IDENTITY(1,1) NOT NULL,
  1682. ServerName NVARCHAR(128),
  1683. CheckDate DATETIME,
  1684. DatabaseID INT NOT NULL,
  1685. FileID INT NOT NULL,
  1686. DatabaseName NVARCHAR(256) ,
  1687. FileLogicalName NVARCHAR(256) ,
  1688. TypeDesc NVARCHAR(60) ,
  1689. SizeOnDiskMB BIGINT ,
  1690. io_stall_read_ms BIGINT ,
  1691. num_of_reads BIGINT ,
  1692. bytes_read BIGINT ,
  1693. io_stall_write_ms BIGINT ,
  1694. num_of_writes BIGINT ,
  1695. bytes_written BIGINT,
  1696. PhysicalName NVARCHAR(520) ,
  1697. DetailsInt INT NULL,
  1698. CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
  1699. + ' INSERT '
  1700. + @OutputTableNameFileStats
  1701. + ' (ServerName, CheckDate, DatabaseID, FileID, DatabaseName, FileLogicalName, TypeDesc, SizeOnDiskMB, io_stall_read_ms, num_of_reads, bytes_read, io_stall_write_ms, num_of_writes, bytes_written, PhysicalName) SELECT '''
  1702. + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
  1703. + ''', ''' + CONVERT(NVARCHAR(100), @StartSampleTime, 127) + ''', '
  1704. + 'DatabaseID, FileID, DatabaseName, FileLogicalName, TypeDesc, SizeOnDiskMB, io_stall_read_ms, num_of_reads, bytes_read, io_stall_write_ms, num_of_writes, bytes_written, PhysicalName FROM #FileStats WHERE Pass = 2';
  1705. EXEC(@StringToExecute);
  1706. END
  1707. ELSE IF (SUBSTRING(@OutputTableNameFileStats, 2, 1) = '#')
  1708. BEGIN
  1709. RAISERROR('Due to the nature of Dymamic SQL, only global (i.e. double pound (##)) temp tables are supported for @OutputTableName', 16, 0)
  1710. END
  1711.  
  1712.  
  1713. /* @OutputTableNamePerfmonStats lets us export the results to a permanent table */
  1714. IF @OutputDatabaseName IS NOT NULL
  1715. AND @OutputSchemaName IS NOT NULL
  1716. AND @OutputTableNamePerfmonStats IS NOT NULL
  1717. AND @OutputTableNamePerfmonStats NOT LIKE '#%'
  1718. AND EXISTS ( SELECT *
  1719. FROM sys.databases
  1720. WHERE QUOTENAME([name]) = @OutputDatabaseName)
  1721. BEGIN
  1722. /* Create the table */
  1723. SET @StringToExecute = 'USE '
  1724. + @OutputDatabaseName
  1725. + '; IF EXISTS(SELECT * FROM '
  1726. + @OutputDatabaseName
  1727. + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
  1728. + @OutputSchemaName
  1729. + ''') AND NOT EXISTS (SELECT * FROM '
  1730. + @OutputDatabaseName
  1731. + '.INFORMATION_SCHEMA.TABLES WHERE QUOTENAME(TABLE_SCHEMA) = '''
  1732. + @OutputSchemaName + ''' AND QUOTENAME(TABLE_NAME) = '''
  1733. + @OutputTableNamePerfmonStats + ''') CREATE TABLE '
  1734. + @OutputSchemaName + '.'
  1735. + @OutputTableNamePerfmonStats
  1736. + ' (ID INT IDENTITY(1,1) NOT NULL,
  1737. ServerName NVARCHAR(128),
  1738. CheckDate DATETIME,
  1739. [object_name] NVARCHAR(128) NOT NULL,
  1740. [counter_name] NVARCHAR(128) NOT NULL,
  1741. [instance_name] NVARCHAR(128) NULL,
  1742. [cntr_value] BIGINT NULL,
  1743. [cntr_type] INT NOT NULL,
  1744. [value_delta] BIGINT NULL,
  1745. [value_per_second] DECIMAL(18,2) NULL,
  1746. CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
  1747. EXEC(@StringToExecute);
  1748.  
  1749. /* Create the view */
  1750. SET @ObjectFullName = @OutputDatabaseName + N'.' + @OutputSchemaName + N'.' + @OutputTableNamePerfmonStats_View;
  1751. IF OBJECT_ID(@ObjectFullName) IS NULL
  1752. BEGIN
  1753. SET @StringToExecute = 'USE '
  1754. + @OutputDatabaseName
  1755. + '; EXEC (''CREATE VIEW '
  1756. + @OutputSchemaName + '.'
  1757. + @OutputTableNamePerfmonStats_View + ' AS ' + @LineFeed
  1758. + 'SELECT p.ServerName, p.CheckDate, p.object_name, p.counter_name, p.instance_name' + @LineFeed
  1759. + ', DATEDIFF(ss, pPrior.CheckDate, p.CheckDate) AS ElapsedSeconds' + @LineFeed
  1760. + ', p.cntr_value' + @LineFeed
  1761. + ', p.cntr_type' + @LineFeed
  1762. + ', (p.cntr_value - pPrior.cntr_value) AS cntr_delta' + @LineFeed
  1763. + 'FROM ' + @OutputSchemaName + '.' + @OutputTableNamePerfmonStats + ' p' + @LineFeed
  1764. + 'INNER JOIN ' + @OutputSchemaName + '.' + @OutputTableNamePerfmonStats + ' pPrior ON p.ServerName = pPrior.ServerName AND p.object_name = pPrior.object_name AND p.counter_name = pPrior.counter_name AND p.instance_name = pPrior.instance_name AND p.CheckDate > pPrior.CheckDate' + @LineFeed
  1765. + 'LEFT OUTER JOIN ' + @OutputSchemaName + '.' + @OutputTableNamePerfmonStats + ' pMiddle ON p.ServerName = pMiddle.ServerName AND p.object_name = pMiddle.object_name AND p.counter_name = pMiddle.counter_name AND p.instance_name = pMiddle.instance_name AND p.CheckDate > pMiddle.CheckDate AND pMiddle.CheckDate > pPrior.CheckDate' + @LineFeed
  1766. + 'WHERE pMiddle.ID IS NULL;'')'
  1767. EXEC(@StringToExecute);
  1768. END;
  1769.  
  1770. SET @StringToExecute = N' IF EXISTS(SELECT * FROM '
  1771. + @OutputDatabaseName
  1772. + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
  1773. + @OutputSchemaName + ''') INSERT '
  1774. + @OutputDatabaseName + '.'
  1775. + @OutputSchemaName + '.'
  1776. + @OutputTableNamePerfmonStats
  1777. + ' (ServerName, CheckDate, object_name, counter_name, instance_name, cntr_value, cntr_type, value_delta, value_per_second) SELECT '''
  1778. + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
  1779. + ''', ''' + CONVERT(NVARCHAR(100), @StartSampleTime, 127) + ''', '
  1780. + 'object_name, counter_name, instance_name, cntr_value, cntr_type, value_delta, value_per_second FROM #PerfmonStats WHERE Pass = 2';
  1781. EXEC(@StringToExecute);
  1782.  
  1783. END
  1784. ELSE IF (SUBSTRING(@OutputTableNamePerfmonStats, 2, 2) = '##')
  1785. BEGIN
  1786. SET @StringToExecute = N' IF (OBJECT_ID(''tempdb..'
  1787. + @OutputTableNamePerfmonStats
  1788. + ''') IS NULL) CREATE TABLE '
  1789. + @OutputTableNamePerfmonStats
  1790. + ' (ID INT IDENTITY(1,1) NOT NULL,
  1791. ServerName NVARCHAR(128),
  1792. CheckDate DATETIME,
  1793. [object_name] NVARCHAR(128) NOT NULL,
  1794. [counter_name] NVARCHAR(128) NOT NULL,
  1795. [instance_name] NVARCHAR(128) NULL,
  1796. [cntr_value] BIGINT NULL,
  1797. [cntr_type] INT NOT NULL,
  1798. [value_delta] BIGINT NULL,
  1799. [value_per_second] DECIMAL(18,2) NULL,
  1800. CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
  1801. + ' INSERT '
  1802. + @OutputTableNamePerfmonStats
  1803. + ' (ServerName, CheckDate, object_name, counter_name, instance_name, cntr_value, cntr_type, value_delta, value_per_second) SELECT '''
  1804. + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
  1805. + ''', ''' + CONVERT(NVARCHAR(100), @StartSampleTime, 127) + ''', '
  1806. + 'object_name, counter_name, instance_name, cntr_value, cntr_type, value_delta, value_per_second FROM #PerfmonStats WHERE Pass = 2';
  1807. EXEC(@StringToExecute);
  1808. END
  1809. ELSE IF (SUBSTRING(@OutputTableNamePerfmonStats, 2, 1) = '#')
  1810. BEGIN
  1811. RAISERROR('Due to the nature of Dymamic SQL, only global (i.e. double pound (##)) temp tables are supported for @OutputTableName', 16, 0)
  1812. END
  1813.  
  1814.  
  1815. /* @OutputTableNameWaitStats lets us export the results to a permanent table */
  1816. IF @OutputDatabaseName IS NOT NULL
  1817. AND @OutputSchemaName IS NOT NULL
  1818. AND @OutputTableNameWaitStats IS NOT NULL
  1819. AND @OutputTableNameWaitStats NOT LIKE '#%'
  1820. AND EXISTS ( SELECT *
  1821. FROM sys.databases
  1822. WHERE QUOTENAME([name]) = @OutputDatabaseName)
  1823. BEGIN
  1824. /* Create the table */
  1825. SET @StringToExecute = 'USE '
  1826. + @OutputDatabaseName
  1827. + '; IF EXISTS(SELECT * FROM '
  1828. + @OutputDatabaseName
  1829. + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
  1830. + @OutputSchemaName
  1831. + ''') AND NOT EXISTS (SELECT * FROM '
  1832. + @OutputDatabaseName
  1833. + '.INFORMATION_SCHEMA.TABLES WHERE QUOTENAME(TABLE_SCHEMA) = '''
  1834. + @OutputSchemaName + ''' AND QUOTENAME(TABLE_NAME) = '''
  1835. + @OutputTableNameWaitStats + ''') CREATE TABLE '
  1836. + @OutputSchemaName + '.'
  1837. + @OutputTableNameWaitStats
  1838. + ' (ID INT IDENTITY(1,1) NOT NULL,
  1839. ServerName NVARCHAR(128),
  1840. CheckDate DATETIME,
  1841. wait_type NVARCHAR(60),
  1842. wait_time_ms BIGINT,
  1843. signal_wait_time_ms BIGINT,
  1844. waiting_tasks_count BIGINT ,
  1845. CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
  1846. EXEC(@StringToExecute);
  1847.  
  1848. /* Create the view */
  1849. SET @ObjectFullName = @OutputDatabaseName + N'.' + @OutputSchemaName + N'.' + @OutputTableNameWaitStats_View;
  1850. IF OBJECT_ID(@ObjectFullName) IS NULL
  1851. BEGIN
  1852. SET @StringToExecute = 'USE '
  1853. + @OutputDatabaseName
  1854. + '; EXEC (''CREATE VIEW '
  1855. + @OutputSchemaName + '.'
  1856. + @OutputTableNameWaitStats_View + ' AS ' + @LineFeed
  1857. + 'SELECT w.ServerName, w.CheckDate, w.wait_type' + @LineFeed
  1858. + ', DATEDIFF(ss, wPrior.CheckDate, w.CheckDate) AS ElapsedSeconds' + @LineFeed
  1859. + ', (w.wait_time_ms - wPrior.wait_time_ms) AS wait_time_ms_delta' + @LineFeed
  1860. + ', (w.signal_wait_time_ms - wPrior.signal_wait_time_ms) AS signal_wait_time_ms_delta' + @LineFeed
  1861. + ', (w.waiting_tasks_count - wPrior.waiting_tasks_count) AS waiting_tasks_count_delta' + @LineFeed
  1862. + 'FROM ' + @OutputSchemaName + '.' + @OutputTableNameWaitStats + ' w' + @LineFeed
  1863. + 'INNER JOIN ' + @OutputSchemaName + '.' + @OutputTableNameWaitStats + ' wPrior ON w.ServerName = wPrior.ServerName AND w.wait_type = wPrior.wait_type AND w.CheckDate > wPrior.CheckDate' + @LineFeed
  1864. + 'LEFT OUTER JOIN ' + @OutputSchemaName + '.' + @OutputTableNameWaitStats + ' wMiddle ON w.ServerName = wMiddle.ServerName AND w.wait_type = wMiddle.wait_type AND w.CheckDate > wMiddle.CheckDate AND wMiddle.CheckDate > wPrior.CheckDate' + @LineFeed
  1865. + 'WHERE wMiddle.ID IS NULL;'')'
  1866. EXEC(@StringToExecute);
  1867. END
  1868.  
  1869.  
  1870. SET @StringToExecute = N' IF EXISTS(SELECT * FROM '
  1871. + @OutputDatabaseName
  1872. + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
  1873. + @OutputSchemaName + ''') INSERT '
  1874. + @OutputDatabaseName + '.'
  1875. + @OutputSchemaName + '.'
  1876. + @OutputTableNameWaitStats
  1877. + ' (ServerName, CheckDate, wait_type, wait_time_ms, signal_wait_time_ms, waiting_tasks_count) SELECT '''
  1878. + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
  1879. + ''', ''' + CONVERT(NVARCHAR(100), @StartSampleTime, 127) + ''', '
  1880. + 'wait_type, wait_time_ms, signal_wait_time_ms, waiting_tasks_count FROM #WaitStats WHERE Pass = 2 AND wait_time_ms > 0 AND waiting_tasks_count > 0';
  1881. EXEC(@StringToExecute);
  1882. END
  1883. ELSE IF (SUBSTRING(@OutputTableNameWaitStats, 2, 2) = '##')
  1884. BEGIN
  1885. SET @StringToExecute = N' IF (OBJECT_ID(''tempdb..'
  1886. + @OutputTableNameWaitStats
  1887. + ''') IS NULL) CREATE TABLE '
  1888. + @OutputTableNameWaitStats
  1889. + ' (ID INT IDENTITY(1,1) NOT NULL,
  1890. ServerName NVARCHAR(128),
  1891. CheckDate DATETIME,
  1892. wait_type NVARCHAR(60),
  1893. wait_time_ms BIGINT,
  1894. signal_wait_time_ms BIGINT,
  1895. waiting_tasks_count BIGINT ,
  1896. CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
  1897. + ' INSERT '
  1898. + @OutputTableNameWaitStats
  1899. + ' (ServerName, CheckDate, wait_type, wait_time_ms, signal_wait_time_ms, waiting_tasks_count) SELECT '''
  1900. + CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
  1901. + ''', ''' + CONVERT(NVARCHAR(100), @StartSampleTime, 127) + ''', '
  1902. + 'wait_type, wait_time_ms, signal_wait_time_ms, waiting_tasks_count FROM #WaitStats WHERE Pass = 2 AND wait_time_ms > 0 AND waiting_tasks_count > 0';
  1903. EXEC(@StringToExecute);
  1904. END
  1905. ELSE IF (SUBSTRING(@OutputTableNameWaitStats, 2, 1) = '#')
  1906. BEGIN
  1907. RAISERROR('Due to the nature of Dymamic SQL, only global (i.e. double pound (##)) temp tables are supported for @OutputTableName', 16, 0)
  1908. END
  1909.  
  1910.  
  1911.  
  1912.  
  1913. DECLARE @separator AS VARCHAR(1);
  1914. IF @OutputType = 'RSV'
  1915. SET @separator = CHAR(31);
  1916. ELSE
  1917. SET @separator = ',';
  1918.  
  1919. IF @OutputType = 'COUNT'
  1920. BEGIN
  1921. SELECT COUNT(*) AS Warnings
  1922. FROM #AskBrentResults
  1923. END
  1924. ELSE
  1925. IF @OutputType = 'Opserver1'
  1926. BEGIN
  1927.  
  1928. SELECT r.[Priority] ,
  1929. r.[FindingsGroup] ,
  1930. r.[Finding] ,
  1931. r.[URL] ,
  1932. r.[Details],
  1933. r.[HowToStopIt] ,
  1934. r.[CheckID] ,
  1935. r.[StartTime],
  1936. r.[LoginName],
  1937. r.[NTUserName],
  1938. r.[OriginalLoginName],
  1939. r.[ProgramName],
  1940. r.[HostName],
  1941. r.[DatabaseID],
  1942. r.[DatabaseName],
  1943. r.[OpenTransactionCount],
  1944. r.[QueryPlan],
  1945. r.[QueryText],
  1946. qsNow.plan_handle AS PlanHandle,
  1947. qsNow.sql_handle AS SqlHandle,
  1948. qsNow.statement_start_offset AS StatementStartOffset,
  1949. qsNow.statement_end_offset AS StatementEndOffset,
  1950. [Executions] = qsNow.execution_count - (COALESCE(qsFirst.execution_count, 0)),
  1951. [ExecutionsPercent] = CAST(100.0 * (qsNow.execution_count - (COALESCE(qsFirst.execution_count, 0))) / (qsTotal.execution_count - qsTotalFirst.execution_count) AS DECIMAL(6,2)),
  1952. [Duration] = qsNow.total_elapsed_time - (COALESCE(qsFirst.total_elapsed_time, 0)),
  1953. [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)),
  1954. [CPU] = qsNow.total_worker_time - (COALESCE(qsFirst.total_worker_time, 0)),
  1955. [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)),
  1956. [Reads] = qsNow.total_logical_reads - (COALESCE(qsFirst.total_logical_reads, 0)),
  1957. [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)),
  1958. [PlanCreationTime] = CONVERT(NVARCHAR(100), qsNow.creation_time ,121),
  1959. [TotalExecutions] = qsNow.execution_count,
  1960. [TotalExecutionsPercent] = CAST(100.0 * qsNow.execution_count / qsTotal.execution_count AS DECIMAL(6,2)),
  1961. [TotalDuration] = qsNow.total_elapsed_time,
  1962. [TotalDurationPercent] = CAST(100.0 * qsNow.total_elapsed_time / qsTotal.total_elapsed_time AS DECIMAL(6,2)),
  1963. [TotalCPU] = qsNow.total_worker_time,
  1964. [TotalCPUPercent] = CAST(100.0 * qsNow.total_worker_time / qsTotal.total_worker_time AS DECIMAL(6,2)),
  1965. [TotalReads] = qsNow.total_logical_reads,
  1966. [TotalReadsPercent] = CAST(100.0 * qsNow.total_logical_reads / qsTotal.total_logical_reads AS DECIMAL(6,2)),
  1967. r.[DetailsInt]
  1968. FROM #AskBrentResults r
  1969. LEFT OUTER JOIN #QueryStats qsTotal ON qsTotal.Pass = 0
  1970. LEFT OUTER JOIN #QueryStats qsTotalFirst ON qsTotalFirst.Pass = -1
  1971. LEFT OUTER JOIN #QueryStats qsNow ON r.QueryStatsNowID = qsNow.ID
  1972. LEFT OUTER JOIN #QueryStats qsFirst ON r.QueryStatsFirstID = qsFirst.ID
  1973. ORDER BY r.Priority ,
  1974. r.FindingsGroup ,
  1975. CASE
  1976. WHEN r.CheckID = 6 THEN DetailsInt
  1977. ELSE 0
  1978. END DESC,
  1979. r.Finding,
  1980. r.ID;
  1981. END
  1982. ELSE IF @OutputType IN ( 'CSV', 'RSV' )
  1983. BEGIN
  1984.  
  1985. SELECT Result = CAST([Priority] AS NVARCHAR(100))
  1986. + @separator + CAST(CheckID AS NVARCHAR(100))
  1987. + @separator + COALESCE([FindingsGroup],
  1988. '(N/A)') + @separator
  1989. + COALESCE([Finding], '(N/A)') + @separator
  1990. + COALESCE(DatabaseName, '(N/A)') + @separator
  1991. + COALESCE([URL], '(N/A)') + @separator
  1992. + COALESCE([Details], '(N/A)')
  1993. FROM #AskBrentResults
  1994. ORDER BY Priority ,
  1995. FindingsGroup ,
  1996. CASE
  1997. WHEN CheckID = 6 THEN DetailsInt
  1998. ELSE 0
  1999. END DESC,
  2000. Finding,
  2001. Details;
  2002. END
  2003. ELSE IF @ExpertMode = 0 AND @OutputXMLasNVARCHAR = 0
  2004. BEGIN
  2005. SELECT [Priority] ,
  2006. [FindingsGroup] ,
  2007. [Finding] ,
  2008. [URL] ,
  2009. CAST(@StockDetailsHeader + [Details] + @StockDetailsFooter AS XML) AS Details,
  2010. CAST(@StockWarningHeader + HowToStopIt + @StockWarningFooter AS XML) AS HowToStopIt,
  2011. [QueryText],
  2012. [QueryPlan]
  2013. FROM #AskBrentResults
  2014. WHERE (@Seconds > 0 OR (Priority IN (0, 250, 251, 255))) /* For @Seconds = 0, filter out broken checks for now */
  2015. ORDER BY Priority ,
  2016. FindingsGroup ,
  2017. CASE
  2018. WHEN CheckID = 6 THEN DetailsInt
  2019. ELSE 0
  2020. END DESC,
  2021. Finding,
  2022. ID;
  2023. END
  2024. ELSE IF @ExpertMode = 0 AND @OutputXMLasNVARCHAR = 1
  2025. BEGIN
  2026. SELECT [Priority] ,
  2027. [FindingsGroup] ,
  2028. [Finding] ,
  2029. [URL] ,
  2030. CAST(@StockDetailsHeader + [Details] + @StockDetailsFooter AS NVARCHAR(MAX)) AS Details,
  2031. CAST([HowToStopIt] AS NVARCHAR(MAX)) AS HowToStopIt,
  2032. CAST([QueryText] AS NVARCHAR(MAX)) AS QueryText,
  2033. CAST([QueryPlan] AS NVARCHAR(MAX)) AS QueryPlan
  2034. FROM #AskBrentResults
  2035. WHERE (@Seconds > 0 OR (Priority IN (0, 250, 251, 255))) /* For @Seconds = 0, filter out broken checks for now */
  2036. ORDER BY Priority ,
  2037. FindingsGroup ,
  2038. CASE
  2039. WHEN CheckID = 6 THEN DetailsInt
  2040. ELSE 0
  2041. END DESC,
  2042. Finding,
  2043. ID;
  2044. END
  2045. ELSE IF @ExpertMode = 1
  2046. BEGIN
  2047. SELECT r.[Priority] ,
  2048. r.[FindingsGroup] ,
  2049. r.[Finding] ,
  2050. r.[URL] ,
  2051. CAST(@StockDetailsHeader + r.[Details] + @StockDetailsFooter AS XML) AS Details,
  2052. CAST(@StockWarningHeader + r.HowToStopIt + @StockWarningFooter AS XML) AS HowToStopIt,
  2053. r.[CheckID] ,
  2054. r.[StartTime],
  2055. r.[LoginName],
  2056. r.[NTUserName],
  2057. r.[OriginalLoginName],
  2058. r.[ProgramName],
  2059. r.[HostName],
  2060. r.[DatabaseID],
  2061. r.[DatabaseName],
  2062. r.[OpenTransactionCount],
  2063. r.[QueryPlan],
  2064. r.[QueryText],
  2065. qsNow.plan_handle AS PlanHandle,
  2066. qsNow.sql_handle AS SqlHandle,
  2067. qsNow.statement_start_offset AS StatementStartOffset,
  2068. qsNow.statement_end_offset AS StatementEndOffset,
  2069. [Executions] = qsNow.execution_count - (COALESCE(qsFirst.execution_count, 0)),
  2070. [ExecutionsPercent] = CAST(100.0 * (qsNow.execution_count - (COALESCE(qsFirst.execution_count, 0))) / (qsTotal.execution_count - qsTotalFirst.execution_count) AS DECIMAL(6,2)),
  2071. [Duration] = qsNow.total_elapsed_time - (COALESCE(qsFirst.total_elapsed_time, 0)),
  2072. [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)),
  2073. [CPU] = qsNow.total_worker_time - (COALESCE(qsFirst.total_worker_time, 0)),
  2074. [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)),
  2075. [Reads] = qsNow.total_logical_reads - (COALESCE(qsFirst.total_logical_reads, 0)),
  2076. [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)),
  2077. [PlanCreationTime] = CONVERT(NVARCHAR(100), qsNow.creation_time ,121),
  2078. [TotalExecutions] = qsNow.execution_count,
  2079. [TotalExecutionsPercent] = CAST(100.0 * qsNow.execution_count / qsTotal.execution_count AS DECIMAL(6,2)),
  2080. [TotalDuration] = qsNow.total_elapsed_time,
  2081. [TotalDurationPercent] = CAST(100.0 * qsNow.total_elapsed_time / qsTotal.total_elapsed_time AS DECIMAL(6,2)),
  2082. [TotalCPU] = qsNow.total_worker_time,
  2083. [TotalCPUPercent] = CAST(100.0 * qsNow.total_worker_time / qsTotal.total_worker_time AS DECIMAL(6,2)),
  2084. [TotalReads] = qsNow.total_logical_reads,
  2085. [TotalReadsPercent] = CAST(100.0 * qsNow.total_logical_reads / qsTotal.total_logical_reads AS DECIMAL(6,2)),
  2086. r.[DetailsInt]
  2087. FROM #AskBrentResults r
  2088. LEFT OUTER JOIN #QueryStats qsTotal ON qsTotal.Pass = 0
  2089. LEFT OUTER JOIN #QueryStats qsTotalFirst ON qsTotalFirst.Pass = -1
  2090. LEFT OUTER JOIN #QueryStats qsNow ON r.QueryStatsNowID = qsNow.ID
  2091. LEFT OUTER JOIN #QueryStats qsFirst ON r.QueryStatsFirstID = qsFirst.ID
  2092. WHERE (@Seconds > 0 OR (Priority IN (0, 250, 251, 255))) /* For @Seconds = 0, filter out broken checks for now */
  2093. ORDER BY r.Priority ,
  2094. r.FindingsGroup ,
  2095. CASE
  2096. WHEN r.CheckID = 6 THEN DetailsInt
  2097. ELSE 0
  2098. END DESC,
  2099. r.Finding,
  2100. r.ID;
  2101.  
  2102. -------------------------
  2103. --What happened: #WaitStats
  2104. -------------------------
  2105. ;with max_batch as (
  2106. select max(SampleTime) as SampleTime
  2107. from #WaitStats
  2108. )
  2109. SELECT
  2110. 'WAIT STATS' as Pattern,
  2111. b.SampleTime as [Sample Ended],
  2112. datediff(ss,wd1.SampleTime, wd2.SampleTime) as [Seconds Sample],
  2113. wd1.wait_type,
  2114. c.[Wait Time (Seconds)],
  2115. c.[Signal Wait Time (Seconds)],
  2116. CASE WHEN c.[Wait Time (Seconds)] > 0
  2117. THEN CAST(100.*(c.[Signal Wait Time (Seconds)]/c.[Wait Time (Seconds)]) as NUMERIC(4,1))
  2118. ELSE 0 END AS [Percent Signal Waits],
  2119. (wd2.waiting_tasks_count - wd1.waiting_tasks_count) AS [Number of Waits],
  2120. CASE WHEN (wd2.waiting_tasks_count - wd1.waiting_tasks_count) > 0
  2121. THEN
  2122. cast((wd2.wait_time_ms-wd1.wait_time_ms)/
  2123. (1.0*(wd2.waiting_tasks_count - wd1.waiting_tasks_count)) as numeric(12,1))
  2124. ELSE 0 END AS [Avg ms Per Wait]
  2125. FROM max_batch b
  2126. JOIN #WaitStats wd2 on
  2127. wd2.SampleTime =b.SampleTime
  2128. JOIN #WaitStats wd1 ON
  2129. wd1.wait_type=wd2.wait_type AND
  2130. wd2.SampleTime > wd1.SampleTime
  2131. CROSS APPLY (SELECT
  2132. cast((wd2.wait_time_ms-wd1.wait_time_ms)/1000. as numeric(12,1)) as [Wait Time (Seconds)],
  2133. cast((wd2.signal_wait_time_ms - wd1.signal_wait_time_ms)/1000. as numeric(12,1)) as [Signal Wait Time (Seconds)]) AS c
  2134. WHERE (wd2.waiting_tasks_count - wd1.waiting_tasks_count) > 0
  2135. and wd2.wait_time_ms-wd1.wait_time_ms > 0
  2136. ORDER BY [Wait Time (Seconds)] DESC;
  2137.  
  2138.  
  2139. -------------------------
  2140. --What happened: #FileStats
  2141. -------------------------
  2142. WITH readstats as (
  2143. SELECT 'PHYSICAL READS' as Pattern,
  2144. ROW_NUMBER() over (order by wd2.avg_stall_read_ms desc) as StallRank,
  2145. wd2.SampleTime as [Sample Time],
  2146. datediff(ss,wd1.SampleTime, wd2.SampleTime) as [Sample (seconds)],
  2147. wd1.DatabaseName ,
  2148. wd1.FileLogicalName AS [File Name],
  2149. UPPER(SUBSTRING(wd1.PhysicalName, 1, 2)) AS [Drive] ,
  2150. wd1.SizeOnDiskMB ,
  2151. ( wd2.num_of_reads - wd1.num_of_reads ) AS [# Reads/Writes],
  2152. CASE WHEN wd2.num_of_reads - wd1.num_of_reads > 0
  2153. THEN CAST(( wd2.bytes_read - wd1.bytes_read)/1024./1024. AS NUMERIC(21,1))
  2154. ELSE 0
  2155. END AS [MB Read/Written],
  2156. wd2.avg_stall_read_ms AS [Avg Stall (ms)],
  2157. wd1.PhysicalName AS [file physical name]
  2158. FROM #FileStats wd2
  2159. JOIN #FileStats wd1 ON wd2.SampleTime > wd1.SampleTime
  2160. AND wd1.DatabaseID = wd2.DatabaseID
  2161. AND wd1.FileID = wd2.FileID
  2162. ),
  2163. writestats as (
  2164. SELECT
  2165. 'PHYSICAL WRITES' as Pattern,
  2166. ROW_NUMBER() over (order by wd2.avg_stall_write_ms desc) as StallRank,
  2167. wd2.SampleTime as [Sample Time],
  2168. datediff(ss,wd1.SampleTime, wd2.SampleTime) as [Sample (seconds)],
  2169. wd1.DatabaseName ,
  2170. wd1.FileLogicalName AS [File Name],
  2171. UPPER(SUBSTRING(wd1.PhysicalName, 1, 2)) AS [Drive] ,
  2172. wd1.SizeOnDiskMB ,
  2173. ( wd2.num_of_writes - wd1.num_of_writes ) AS [# Reads/Writes],
  2174. CASE WHEN wd2.num_of_writes - wd1.num_of_writes > 0
  2175. THEN CAST(( wd2.bytes_written - wd1.bytes_written)/1024./1024. AS NUMERIC(21,1))
  2176. ELSE 0
  2177. END AS [MB Read/Written],
  2178. wd2.avg_stall_write_ms AS [Avg Stall (ms)],
  2179. wd1.PhysicalName AS [file physical name]
  2180. FROM #FileStats wd2
  2181. JOIN #FileStats wd1 ON wd2.SampleTime > wd1.SampleTime
  2182. AND wd1.DatabaseID = wd2.DatabaseID
  2183. AND wd1.FileID = wd2.FileID
  2184. )
  2185. SELECT
  2186. Pattern, [Sample Time], [Sample (seconds)], [File Name], [Drive], [# Reads/Writes],[MB Read/Written],[Avg Stall (ms)], [file physical name]
  2187. from readstats
  2188. where StallRank <=5 and [MB Read/Written] > 0
  2189. union all
  2190. SELECT Pattern, [Sample Time], [Sample (seconds)], [File Name], [Drive], [# Reads/Writes],[MB Read/Written],[Avg Stall (ms)], [file physical name]
  2191. from writestats
  2192. where StallRank <=5 and [MB Read/Written] > 0;
  2193.  
  2194.  
  2195. -------------------------
  2196. --What happened: #PerfmonStats
  2197. -------------------------
  2198.  
  2199. SELECT 'PERFMON' AS Pattern, pLast.[object_name], pLast.counter_name, pLast.instance_name,
  2200. pFirst.SampleTime AS FirstSampleTime, pFirst.cntr_value AS FirstSampleValue,
  2201. pLast.SampleTime AS LastSampleTime, pLast.cntr_value AS LastSampleValue,
  2202. pLast.cntr_value - pFirst.cntr_value AS ValueDelta,
  2203. ((1.0 * pLast.cntr_value - pFirst.cntr_value) / DATEDIFF(ss, pFirst.SampleTime, pLast.SampleTime)) AS ValuePerSecond
  2204. FROM #PerfmonStats pLast
  2205. 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))
  2206. AND pLast.ID > pFirst.ID
  2207. ORDER BY Pattern, pLast.[object_name], pLast.counter_name, pLast.instance_name
  2208.  
  2209.  
  2210. -------------------------
  2211. --What happened: #FileStats
  2212. -------------------------
  2213. SELECT qsNow.*, qsFirst.*
  2214. FROM #QueryStats qsNow
  2215. 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
  2216. WHERE qsNow.Pass = 2
  2217. END
  2218.  
  2219. DROP TABLE #AskBrentResults;
  2220.  
  2221.  
  2222. END /* IF @Question IS NULL */
  2223. ELSE IF @Question IS NOT NULL
  2224.  
  2225. /* We're playing Magic SQL 8 Ball, so give them an answer. */
  2226. BEGIN
  2227. IF OBJECT_ID('tempdb..#BrentAnswers') IS NOT NULL
  2228. DROP TABLE #BrentAnswers;
  2229. CREATE TABLE #BrentAnswers(Answer VARCHAR(200) NOT NULL);
  2230. INSERT INTO #BrentAnswers VALUES ('It sounds like a SAN problem.');
  2231. INSERT INTO #BrentAnswers VALUES ('You know what you need? Bacon.');
  2232. INSERT INTO #BrentAnswers VALUES ('Talk to the developers about that.');
  2233. INSERT INTO #BrentAnswers VALUES ('Let''s post that on StackOverflow.com and find out.');
  2234. INSERT INTO #BrentAnswers VALUES ('Have you tried adding an index?');
  2235. INSERT INTO #BrentAnswers VALUES ('Have you tried dropping an index?');
  2236. INSERT INTO #BrentAnswers VALUES ('You can''t prove anything.');
  2237. INSERT INTO #BrentAnswers VALUES ('If you watched our Tuesday webcasts, you''d already know the answer to that.');
  2238. INSERT INTO #BrentAnswers VALUES ('Please phrase the question in the form of an answer.');
  2239. INSERT INTO #BrentAnswers VALUES ('Outlook not so good. Access even worse.');
  2240. INSERT INTO #BrentAnswers VALUES ('Did you try asking the rubber duck? http://www.codinghorror.com/blog/2012/03/rubber-duck-problem-solving.html');
  2241. INSERT INTO #BrentAnswers VALUES ('Oooo, I read about that once.');
  2242. INSERT INTO #BrentAnswers VALUES ('I feel your pain.');
  2243. INSERT INTO #BrentAnswers VALUES ('http://LMGTFY.com');
  2244. INSERT INTO #BrentAnswers VALUES ('No comprende Ingles, senor.');
  2245. INSERT INTO #BrentAnswers VALUES ('I don''t have that problem on my Mac.');
  2246. INSERT INTO #BrentAnswers VALUES ('Is Priority Boost on?');
  2247. INSERT INTO #BrentAnswers VALUES ('Have you tried rebooting your machine?');
  2248. INSERT INTO #BrentAnswers VALUES ('Try defragging your cursors.');
  2249. INSERT INTO #BrentAnswers VALUES ('Why are you wearing that? Do you have a job interview later or something?');
  2250. INSERT INTO #BrentAnswers VALUES ('I''m ashamed that you don''t know the answer to that question.');
  2251. INSERT INTO #BrentAnswers VALUES ('What do I look like, a Microsoft Certified Master? Oh, wait...');
  2252. INSERT INTO #BrentAnswers VALUES ('Duh, Debra.');
  2253. SELECT TOP 1 Answer FROM #BrentAnswers ORDER BY NEWID();
  2254. END
  2255.  
  2256. END /* ELSE IF @OutputType = 'SCHEMA' */
  2257.  
  2258. SET NOCOUNT OFF;
  2259. GO
  2260.  
  2261.  
  2262. /* How to run it:
  2263. EXEC dbo.sp_AskBrent
  2264.  
  2265. With extra diagnostic info:
  2266. EXEC dbo.sp_AskBrent @ExpertMode = 1;
  2267.  
  2268. In Ask a Question mode:
  2269. EXEC dbo.sp_AskBrent 'Is this cursor bad?';
  2270.  
  2271. Saving output to tables:
  2272. EXEC sp_AskBrent @Seconds = 60
  2273. , @OutputDatabaseName = 'DBAtools'
  2274. , @OutputSchemaName = 'dbo'
  2275. , @OutputTableName = 'AskBrentResults'
  2276. , @OutputTableNameFileStats = 'AskBrentResults_FileStats'
  2277. , @OutputTableNamePerfmonStats = 'AskBrentResults_PerfmonStats'
  2278. , @OutputTableNameWaitStats = 'AskBrentResults_WaitStats'
  2279. */
Advertisement
Add Comment
Please, Sign In to add comment