Thursday, September 28, 2017

SSRS failing to come online.

We got an incident where SSRS reports were inaccessible. When checked SSRS was stopped. I tried starting it, it was failing to come online. In the eventvwr we see the below warnings in the systems log

The SQL Server Reporting Services (MSSQLSERVER) service failed to start due to the following error:
The service did not respond to the start or control request in a timely fashion.

In “Applications log” we see..

Windows detected your registry file is still in use by other applications or services. The file will be unloaded now. The applications or services that hold your registry file may not function properly afterwards. 

DETAIL -
 15 user registry handles leaked from \Registry\User\S-1-5-21-1758020066-803956685-1919233885-192659:
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659\Software\Microsoft\SystemCertificates\My
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659\Software\Microsoft\SystemCertificates\CA
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659\Software\Microsoft\SystemCertificates\TrustedPeople
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659\Software\Microsoft\SystemCertificates\Disallowed
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659\Control Panel\International
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659\Software\Microsoft\SystemCertificates\Root
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659\Software\Policies\Microsoft\SystemCertificates
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659\Software\Microsoft\SystemCertificates\SmartCardRoot
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659\Software\Microsoft\SystemCertificates\trust
Process 4284 (\Device\HarddiskVolume4\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe) has opened key \REGISTRY\USER\S-1-5-21-1758020066-803956685-1919233885-192659\Software\Microsoft\Windows\CurrentVersion\Explorer


Resolution


2nd workaround: from the above link helped get SSRS online.

2nd workaround:
If the first action plan didn’t work, try disabled the certificate checking in the ReportingServicesService.exe.config file:

  1. Edit the ReportingServicesService.exe.config file usually located in this folder F:\mssql2008\MSRS10_50.MSSQLSERVER\Reporting Services\ReportServer\bin\ReportingServicesService.exe.config
  2. Add the “<generatePublisherEvidence enabled=”false”/>” within the <Runtime> tag
  3. Patch the server with the KB. – In this case I didn’t have to patch it as it is already on the latest patch.

Tuesday, August 15, 2017

Wrapper scripts

SQL Server 2008 Wrapper script to get a detailed list of server configurations.


Print 'Server Name,Server Type,Server Version, Edition , service pack and platform

'
set nocount on
SELECT @@Servername AS ServerName ,
+ ' '+ CASE
WHEN Substring(@@version,len(@@version)-4,4)='(VM)' THEN 'VM'
ELSE 'PHYSICAL'
END AS 'Server Type',
@@version AS 'Server Version, Edition , service pack and platform'

Print '

'
Print'Quick view of SQL Server Details

'
Set Nocount on
--Declare the variables
DECLARE @UserDefinedObjects INT
--Set the variables
SET @UserDefinedObjects=0

SELECT
CASE
WHEN Len(CONVERT(sysname, SERVERPROPERTY('InstanceName')))>0 THEN SERVERPROPERTY('InstanceName')
ELSE 'Default Instance'
END AS 'Named/Default Instance',
CASE
WHEN SERVERPROPERTY('IsClustered')=1 THEN 'YES'
ELSE 'NO'
END AS 'IsClustered',
CASE
WHEN EXISTS ( SELECT * FROM [master].[sys].[all_objects]  WITH (NOLOCK) WHERE name like 'xp_sqllitespeed%') THEN 'YES'
ELSE 'NO'
END AS 'SQLLiteSpeed Installed',
CASE
WHEN SERVERPROPERTY('IsFullTextInstalled')=1 THEN 'YES'
ELSE 'NO'
END AS 'IsFullTextInstalled',
CASE
WHEN EXISTS (SELECT * FROM [msdb].[dbo].[log_shipping_primary_databases]  WITH (NOLOCK) ) THEN 'YES'
WHEN EXISTS (SELECT * FROM [msdb].[dbo].[log_shipping_primary_secondaries]  WITH (NOLOCK) ) THEN 'YES'
ELSE 'NO'
END AS 'Log Shipping',
CASE
WHEN EXISTS (SELECT * FROM [msdb].[sys].[database_mirroring]  WITH (NOLOCK) WHERE mirroring_partner_name IS NOT NULL) THEN 'YES'
ELSE 'NO'
END AS 'Database Mirroring',
CASE
WHEN EXISTS (SELECT *  FROM [master].[sys].[databases]  WITH (NOLOCK) WHERE (is_published=1 OR is_subscribed=1 OR is_merge_published=1 OR is_distributor=1)) THEN 'YES'
ELSE 'NO'
END AS 'Replication',
CASE
WHEN EXISTS (SELECT * FROM [master].[sys].[servers]  WITH (NOLOCK) WHERE is_linked=1) THEN 'YES'
ELSE 'NO'
END AS 'Linked Servers',
   CASE
WHEN EXISTS ( SELECT * FROM [msdb].[dbo].[sysssispackages] WITH (NOLOCK) ) THEN 'YES'
ELSE 'NO'
END AS 'SSIS Packages',
CASE
WHEN EXISTS ( SELECT * FROM [msdb].[dbo].[sysmaintplan_plans] WITH (NOLOCK) ) THEN 'YES'
ELSE 'NO'
END AS 'Maintenance Plans',
CASE
WHEN NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmail_profile] WITH (NOLOCK) ) THEN 'NO'
       ELSE 'YES'
END AS 'DBMail',
CASE
WHEN EXISTS ( SELECT * FROM [msdb].[dbo].[sysoperators] WITH (NOLOCK) ) THEN 'YES'
ELSE 'NO'
END AS 'Operators',
CASE
WHEN EXISTS ( SELECT * FROM [msdb].[dbo].[sysalerts] WITH (NOLOCK) ) THEN 'YES'
ELSE 'NO'
END AS 'Alerts',
CASE
WHEN EXISTS (SELECT * FROM [master].[sys].[all_objects]  WITH (NOLOCK) WHERE type='X' and is_ms_shipped=0) THEN 'YES'
ELSE 'NO'
END AS 'Extended Stored Procedures',
CASE
WHEN @UserDefinedObjects>0 THEN 'YES'
ELSE 'NO'
END AS  'User defined Extended SP''s',
CASE
WHEN EXISTS ( SELECT * FROM [master].[sys].[messages] WITH (NOLOCK) WHERE message_id> 50001 ) THEN 'YES'
ELSE 'NO'
END AS 'UserDefined Messages',
CASE
WHEN EXISTS ( SELECT  * FROM sys.backup_devices WITH (NOLOCK) ) THEN 'YES'
ELSE 'NO'
END AS 'Backup Devices'

Print'

'
Print 'Lists the SQL Server Aliases

'
set nocount on
GO
CREATE TABLE #Alias
(Output VARCHAR(1024))
DECLARE @advoptions varchar(20)
IF EXISTS (SELECT * FROM sys.configurations WHERE name = 'show advanced options' and value_in_use = 0)
BEGIN
USE [master]
EXEC sp_configure 'show advanced option', '1'
RECONFIGURE
SET @advoptions='Advoption'
End

--for xp_cmdshell
DECLARE @XPCMDshell varchar(20)
IF EXISTS (SELECT * FROM sys.configurations WHERE name = 'xp_cmdshell' and value_in_use = 0)
BEGIN
USE [master]
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE
SET @XPCMDshell = 'CmdshellEnabled'
END

if exists(SELECT [name] FROM sys.configurations WHERE NAME LIKE '%64%')
begin
INSERT INTO #Alias exec xp_cmdshell 'reg query "HKLM\SOFTWARE\Wow6432Node\Microsoft\MSSQLServer\Client\ConnectTo"'
DELETE FROM #Alias WHERE Output IS NULL or Output like 'HKEY%'
if exists (select * from #Alias where Output like '%error%')
print 'Aliases not defined'
else
select SQL_Alias_64bit=Output from  #Alias
end

else

begin
INSERT INTO #Alias exec xp_cmdshell 'reg query "HKLM\SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo"'
DELETE FROM #Alias WHERE Output IS NULL or Output like 'HKEY%'
if exists (select * from #Alias where Output like '%error%')
print 'Aliases not defined'
else
select SQL_Alias_32bit=Output from  #Alias
end

drop table #Alias

IF @XPCMDshell = 'CmdshellEnabled'
BEGIN
USE [master]
EXEC sp_configure 'xp_cmdshell', 0
RECONFIGURE

END
IF @advoptions='Advoption'
BEGIN
USE [master]
EXEC sp_configure 'show advanced option', '0'
RECONFIGURE
End

Print'

'
Print 'Host names and Ip addresses that are listed under either LINKEDSERVER_NAME or SRV_DATASOURCE

'
Set nocount on
SELECT CAST(name as varchar(20)) as LINKEDSERVER_NAME,CAST(srv.provider as varchar(15)) as SRV_PROVIDERNAME,
CAST(srv.product as varchar(15)) as SRV_PRODUCT,CAST(srv.data_source as varchar(20)) as SRV_DATASOURCE,
CAST(srv.provider_string as varchar(20)) as SRV_PROVIDERSTRING,CAST(srv.CATALOG as varchar(15)) as SRV_CAT
FROM sys.servers srv WHERE is_linked = 1 and srv.data_source is not null

Print '

'      
Print 'Host names and IP adddress used in master..sysservers

'
Select CAST(srvname as varchar(20)) as ServerName,CAST(providername as varchar(15)) as ProviderName,
CAST(srvproduct as varchar(15)) as ServerProduct,CAST(datasource as varchar(15)) as DataSource,
CAST(providerstring as varchar(15)) as ProviderString,CAST( catalog as varchar(20)) as Catalog
FROM master..sysservers

Print '

'
Print 'Servers Participating in Mirrioring

'
SELECT cast(@@servername as varchar(20)) as Current_Server, CAST(db_name(database_id) as varchar(20))
as Database_Name, CAST(Mirroring_Role_Desc as varchar(15)) as Mirror_Role_Desc ,
CAST(Mirroring_Partner_Name as varchar(30)) as Mirror_Partner_Name ,
CAST(Mirroring_Partner_Instance as varchar(20)) as Mirror_Partner_Instance  ,
CAST(Mirroring_Witness_Name as varchar(15)) as Mirror_Witness_Name
FROM sys.database_mirroring where mirroring_role in (1, 2)

Print '

'
Print'Servers Participating in Logshipping

'
set nocount on
GO
select cast(lp.primary_server as varchar(15)) AS Primary_Server,
cast(lp.primary_database as varchar(15)) AS [Database],
cast(lps.secondary_server as varchar(15)) AS Secondary_Server,
cast(lsp.monitor_server as varchar(15)) AS Monitor_Server
from
master.dbo.sysDatabases SD
inner join msdb.dbo.log_shipping_monitor_primary LP on lp.primary_database=SD.name
inner join msdb.dbo.log_shipping_primary_secondaries lps on sd.name=lps.secondary_database
inner join msdb.dbo.log_shipping_primary_databases lsp on lp.primary_database=lsp.primary_database

Print'

'
Print'Host names and IP adddress used in Sysadmin..Serversettings

'
IF  EXISTS (SELECT * FROM sys.databases WHERE name = N'Sysadmin')
Begin
select * from Sysadmin..ServerSettings where settingname='ServerName'or
 (SettingValue like '%[0-9].[0-9].[0-9].[0-9]%' -- 1.1
or SettingValue like '%[0-9].[0-9].[0-9][0-9].[0-9]%' -- 1.11
or SettingValue like '%[0-9].[0-9].[0-9][0-9][0-9].[0-9]%' -- 1.111
or SettingValue like '%[0-9].[0-9][0-9].[0-9][0-9].[0-9]%' --11.11
or SettingValue like '%[0-9].[0-9][0-9].[0-9].[0-9]%' -- 11.1
or SettingValue like '%[0-9].[0-9][0-9].[0-9][0-9][0-9].[0-9]%' -- 11.111
or SettingValue like '%[0-9].[0-9][0-9][0-9].[0-9][0-9][0-9].[0-9]%' -- 111.111
or SettingValue like '%[0-9].[0-9][0-9][0-9].[0-9][0-9].[0-9]%' -- 111.11
or SettingValue like '%[0-9].[0-9][0-9][0-9].[0-9].[0-9]%') -- 111.1
and SettingValue not like '%[0-9].00.00.[0-9]%'
End

else

Print 'Sysadmin DB Doesnot Exists'

Print '

'
Print 'Host names and IP address used in SQL Agent Job steps

'
Declare @servername varchar(128)
Declare @SQLCMD varchar(2000)
Declare @SQLCMD1 varchar(2000)
Declare @name varchar(2000)
--Retreives the Server  info
 create table #tmpObjectsfound (job_name varchar(200),Step_id varchar(200),step_name varchar(500),serverfound varchar(500),IP_Information varchar(1000))


DECLARE servername_cursor CURSOR READ_ONLY FOR
select srvname from master..sysservers

OPEN servername_cursor

FETCH NEXT FROM servername_cursor
INTO @servername

WHILE @@FETCH_STATUS = 0
BEGIN

Select @SQLCMD = 'select s.name,ss.Step_id,ss.step_name,' + '''' + @servername + '''' + ' as ServernameFound  from msdb..sysjobs s join msdb..sysjobsteps ss on s.job_id=ss.job_id
where command like ' + '''' + '%' + @servername + '%' + ''''
 
insert #tmpObjectsFound (job_name,Step_id,step_name,serverfound)
exec(@SQLCMD)

FETCH NEXT FROM servername_cursor
INTO @servername
END

CLOSE servername_cursor
DEALLOCATE servername_cursor


--Retreives the IP information
declare @localserver varchar (100)
set @localserver=(select @@SERVERNAME)

Select @SQLCMD1 = 'select s.name,ss.Step_id,ss.step_name,
' + '''' + @localserver + '''' + ' as ServernameFound,ss.command from msdb..sysjobs s join msdb..sysjobsteps ss on s.job_id=ss.job_id
where (command like ''%[0-9].[0-9].[0-9].[0-9]%'' -- 1.1
or command like ''%[0-9].[0-9].[0-9][0-9].[0-9]%'' -- 1.11
or command like ''%[0-9].[0-9].[0-9][0-9][0-9].[0-9]%'' -- 1.111
or command like ''%[0-9].[0-9][0-9].[0-9][0-9].[0-9]%'' --11.11
or command like ''%[0-9].[0-9][0-9].[0-9].[0-9]%'' -- 11.1
or command like ''%[0-9].[0-9][0-9].[0-9][0-9][0-9].[0-9]%'' -- 11.111
or command like ''%[0-9].[0-9][0-9][0-9].[0-9][0-9][0-9].[0-9]%'' -- 111.111
or command like ''%[0-9].[0-9][0-9][0-9].[0-9][0-9].[0-9]%'' -- 111.11
or command like ''%[0-9].[0-9][0-9][0-9].[0-9].[0-9]%'') -- 111.1
and command not like ''%[0-9].00.00.[0-9]%'''

insert #tmpObjectsFound (job_name,Step_id,step_name,serverfound,IP_Information)

exec(@SQLCMD1)
select CAST(job_name as varchar(30)) as Job_name,CAST(step_id as int) as step_id,CAST(step_name as varchar(30)) as Step_Name,
cast(serverfound as varchar(20)) as serverfound,cast(ip_information as varchar(50)) as ip_information from #tmpObjectsFound
drop table #tmpObjectsFound

Print '

'
Print 'Lists the DTS Packages

'
select distinct cast(name as varchar(40)) as Name ,cast(owner as varchar(20)) as Owner from msdb..sysdtspackages

Print'

'

Print 'Lists the SQL Services installed

'
SET NOCOUNT ON

--  Temporary Tables
CREATE TABLE #Services
(oOutput VARCHAR(1024))

CREATE TABLE #ServicesDetail
(oOutput VARCHAR(1024))

CREATE TABLE #ServicesDetail1
(oOutput VARCHAR(1024))

CREATE TABLE #ServicesFinal
(ServiceName VARCHAR(200),
ServiceOwner VARCHAR(200),
ServiceStartTp VARCHAR(200),
ServiceBinary VARCHAR(200),
STATE VARCHAR(150))

DECLARE @advanced_options varchar(20)
IF EXISTS (SELECT * FROM sys.configurations WHERE name = 'show advanced options' and value_in_use = 0)
BEGIN
USE [master]
EXEC sp_configure 'show advanced option', '1'
RECONFIGURE
SET @advanced_options='Advoption Enabled'
End

--for xp_cmdshell
DECLARE @XP_CMDshellstatus varchar(20)
IF EXISTS (SELECT * FROM sys.configurations WHERE name = 'xp_cmdshell' and value_in_use = 0)
BEGIN
USE [master]
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE
SET @XP_CMDshellstatus = 'Cmdshell Enabled'
END

-- sc query is used to query the entire service control manager and then filters
-- by anything with "SQL" in it's name.  /I option ignores Case.
INSERT INTO #Services EXEC xp_cmdshell 'sc query state= all |find /I "Reportserver"|find /I "service_name"'
INSERT INTO #Services EXEC xp_cmdshell 'sc query state= all |find /I "sql"|find /I "service_name"'
INSERT INTO #Services EXEC xp_cmdshell 'sc query state= all |find /I "OLAP"|find /I "service_name"'
INSERT INTO #Services EXEC xp_cmdshell 'sc query state= all |find /I "DTS"|find /I "service_name"'


-- Remove NULL records
DELETE FROM #Services WHERE oOutput IS NULL

-- Cursor variables
DECLARE @curServNm  VARCHAR(100)
DECLARE @cCMD       VARCHAR(100)
DECLARE @cBinary    VARCHAR(150)
DECLARE @cOwner     VARCHAR(100)
DECLARE @cStartTp   VARCHAR(100)
DECLARE @cCMD1      VARCHAR(100)
DECLARE @cstate     VARCHAR(100)

DECLARE cCursor CURSOR FOR
SELECT RTRIM(LTRIM(SUBSTRING(oOutPut,PATINDEX('%:%', oOutPut)+1, LEN(oOutPut)) )) AS ServiceName
FROM #Services

OPEN cCursor
FETCH NEXT FROM cCursor INTO @curServNm

 WHILE @@FETCH_STATUS = 0

  BEGIN

   --  Option  to query SC.
   SET @cCMD = 'sc qc "#SERVICENAME#"'
   SET @cCMD = REPLACE(@cCMD, '#SERVICENAME#', @curServNm)
     
    INSERT INTO #ServicesDetail EXEC xp_cmdshell @cCMD

    DELETE FROM #ServicesDetail WHERE oOutput IS NULL
   
    -- second table
   
    SET @cCMD1 = 'sc query "#SERVICENAME#"'
   SET @cCMD1 = REPLACE(@cCMD1, '#SERVICENAME#', @curServNm)
 
 
    INSERT INTO #ServicesDetail1 EXEC xp_cmdshell @cCMD1

    DELETE FROM #ServicesDetail1 WHERE oOutput IS NULL
                         
         
    SELECT @cBinary = RTRIM(LTRIM(SUBSTRING(oOutPut,PATINDEX('%:%', oOutPut)+1, LEN(oOutPut)) ))
    FROM   #ServicesDetail
    WHERE  PATINDEX('%BINARY_PATH_NAME%', oOutPut) > 0
   
    SELECT @cOwner = RTRIM(LTRIM(SUBSTRING(oOutPut,PATINDEX('%:%', oOutPut)+1, LEN(oOutPut)) ))
    FROM   #ServicesDetail
    WHERE  PATINDEX('%SERVICE_START_NAME%:%', oOutPut) > 0
   
    SELECT @cStartTp = RTRIM(LTRIM(SUBSTRING(oOutPut,PATINDEX('%:%', oOutPut)+1, LEN(oOutPut)) ))
    FROM   #ServicesDetail
    WHERE  PATINDEX('%START_TYPE%:%', oOutPut) > 0
   
    SELECT @cstate = RTRIM(LTRIM(SUBSTRING(oOutPut,PATINDEX('%:%', oOutPut)+1, LEN(oOutPut)) ))
    FROM   #ServicesDetail1
    WHERE  PATINDEX('%STATE%:%', oOutPut) > 0

    INSERT INTO #ServicesFinal (
     ServiceName,
     ServiceOwner,
     STATE,
     ServiceStartTp,
     ServiceBinary
      )
    VALUES(
     @curServNm,
     @cOwner,
     @cstate,
     @cStartTp,
     @cBinary)

FETCH NEXT FROM cCursor INTO @curServNm
END

CLOSE cCursor
DEALLOCATE cCursor

-- Final result set
SELECT CAST(ServiceName as varchar(40)) as ServiceName,CAST(ServiceOwner as varchar(30)) as ServiceOwner,
cast (ServiceStartTp as varchar(20)) as ServiceStartTp,cast(State as varchar(15)) as State FROM #ServicesFinal

-- Clean-up objects
IF OBJECT_ID('TempDB.dbo.#Services') IS NOT NULL
 DROP TABLE #Services

IF OBJECT_ID('TempDB.dbo.#ServicesDetail') IS NOT NULL
 DROP TABLE #ServicesDetail


IF OBJECT_ID('TempDB.dbo.#ServicesDetail1') IS NOT NULL
 DROP TABLE #ServicesDetail1

IF OBJECT_ID('TempDB.dbo.#ServicesFinal') IS NOT NULL
 DROP TABLE #ServicesFinal

 IF @XP_CMDshellstatus = 'Cmdshell Enabled'
BEGIN
USE [master]
EXEC sp_configure 'xp_cmdshell', 0
RECONFIGURE

END
IF @advanced_options='Advoption Enabled'
BEGIN
USE [master]
EXEC sp_configure 'show advanced option', '0'
RECONFIGURE
End

Print 'Find all references to sysservers in DDL across all databases

'

Declare @server_name varchar(128)
Declare @DB_Name varchar(128)
Declare @DB_Id int
Declare @SQL_CMD varchar(2000)

Create Table #tmpObjects_Found (dbname varchar(128), objectname varchar(128), ServerFound varchar(128))

DECLARE database_cursor CURSOR READ_ONLY FOR
select name, dbid from master..sysdatabases
where DATABASEPROPERTYEX ( name , 'status' ) = 'ONLINE'
and name != 'tempdb'

OPEN database_cursor

FETCH NEXT FROM database_cursor
INTO @DB_Name, @DB_Id

WHILE @@FETCH_STATUS = 0
BEGIN

DECLARE servername_cursor CURSOR READ_ONLY FOR
select srvname from master..sysservers

OPEN servername_cursor

FETCH NEXT FROM servername_cursor
INTO @server_name

WHILE @@FETCH_STATUS = 0
BEGIN

Select @SQL_CMD = 'select ' + '''' + @DB_Name + '''' + ' as DBName,' + 'object_name(id, ' + convert(varchar(10), @DB_Id) + ') as ObjectName, ' + '''' + @server_name + '''' + ' as ServerFound from ' + '[' + @DB_Name + ']' + '..syscomments (NOLOCK) where text like ' + '''' + '%' + @server_name + '%' + ''''
--print @SQL_CMD
insert #tmpObjects_Found (DBName, ObjectName, ServerFound)
exec(@SQL_CMD)
FETCH NEXT FROM servername_cursor
INTO @server_name
END

CLOSE servername_cursor
DEALLOCATE servername_cursor

FETCH NEXT FROM database_cursor
INTO @DB_Name, @DB_Id
END

CLOSE database_cursor
DEALLOCATE database_cursor

select distinct cast(dbname as varchar(20)) as dbname, cast(objectname as varchar(50)) as objectname, cast(ServerFound as varchar (30)) as Serverfound from #tmpObjects_Found
drop table #tmpObjects_Found

Print '

'
Print 'Ip Address in DDL for all databases

'
--Find Ip Address in DDL for all databases
Declare @servername1 varchar(128)
Declare @DBName varchar(128)
Declare @DBId int
Declare @SQL nvarchar(max)


create table #tmp_Objects_found (database_name varchar(100),schemaname varchar(100),Object_name varchar(200),object_Type varchar(500))

DECLARE database_cursor CURSOR READ_ONLY FOR

select name, dbid from master.sys.sysdatabases where databasepropertyex(name, 'Status') IN ('ONLINE')

OPEN database_cursor

FETCH NEXT FROM database_cursor
INTO @DBName, @DBId

WHILE @@FETCH_STATUS = 0
BEGIN

SET @servername1 = (SELECT @@servername)

SET @SQL = 'USE [' + @DBName + '];                                                    
                                                INSERT INTO #tmp_Objects_found
                                                SELECT DISTINCT ''' + @DBName + ''', OBJECT_SCHEMA_NAME(id),object_name(id),so.type_desc from syscomments sc join sys.objects so on sc.id=so.object_id
where (text like ''%[0-9].[0-9].[0-9].[0-9]%'' -- 1.1
or text like ''%[0-9].[0-9].[0-9][0-9].[0-9]%'' -- 1.11
or text like ''%[0-9].[0-9].[0-9][0-9][0-9].[0-9]%'' -- 1.111
or text like ''%[0-9].[0-9][0-9].[0-9][0-9].[0-9]%'' --11.11
or text like ''%[0-9].[0-9][0-9].[0-9].[0-9]%'' -- 11.1
or text like ''%[0-9].[0-9][0-9].[0-9][0-9][0-9].[0-9]%'' -- 11.111
or text like ''%[0-9].[0-9][0-9][0-9].[0-9][0-9][0-9].[0-9]%'' -- 111.111
or text like ''%[0-9].[0-9][0-9][0-9].[0-9][0-9].[0-9]%'' -- 111.11
or text like ''%[0-9].[0-9][0-9][0-9].[0-9].[0-9]%'') -- 111.1
and text not like ''%[0-9].00.00.[0-9]%'''
--PRINT @SQL
EXEC sp_executesql @SQL;
FETCH NEXT FROM database_cursor
INTO @DBName, @DBId
END

CLOSE database_cursor
DEALLOCATE database_cursor
SELECT CAST(database_name as varchar(20)) as database_name,CAST(schemaname as varchar(15)) as schemaname,
CAST(Object_name as varchar(20)) as Object_name,CAST(object_type as varchar(20)) as object_type
FROM #tmp_Objects_found
DROP TABLE #tmp_Objects_found;

Print '

'
Print 'Script will retreive the last backup date for all

'
SELECT cast(sd.Name as varchar(30)) AS DatabaseName,cast(d.state_desc as varchar(15)) as DBStatus,
COALESCE(CONVERT(VARCHAR(12), MAX(bs.backup_finish_date), 101),'BACKUP NEVER GENERATED') AS LastBackUpDate
FROM sys.sysdatabases sd
LEFT OUTER JOIN msdb.dbo.backupset bs ON bs.database_name = sd.name
join sys.databases d on sd.dbid=d.database_id
where d.state_desc='online'
GROUP BY sd.Name,d.state_desc

Print'

'
Print'Read SQL Error log for any errors

'
CREATE TABLE #SQL_ErrorLog (date varchar(100), processinfo varchar(100),Message varchar(500))
CREATE INDEX errorlog_msg ON #SQL_Errorlog(Message)
INSERT #SQL_ErrorLog EXEC master..xp_readerrorlog 0,1, "Error:"
SELECT cast(date as varchar(25)) AS Date,cast(processinfo as varchar(15)) AS Processinfo,
cast(Message as varchar(100)) AS Message  FROM #SQL_ErrorLog
DROP TABLE #SQL_ErrorLog

use msdb
Print 'List if SSIS packages'
select * from  sysssispackages where packagetype =5 and packageformat <>1

Print 'List of Maintanance Plans'
select * from  sysssispackages where packagetype=6

Saturday, January 7, 2017

Server Activity

-- Server activity. This is an edited version of Brent Ozar's script.


SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO



    DECLARE @Question NVARCHAR(MAX)  ,
    @AsOf DATETIME  ,
@ExpertMode TINYINT = 1 ,
    @Seconds TINYINT = 5 ,
    @OutputType VARCHAR(20) = 'TABLE' ,
    @OutputDatabaseName NVARCHAR(128) = NULL ,
    @OutputSchemaName NVARCHAR(256) = NULL ,
    @OutputTableName NVARCHAR(256) = NULL ,
    @OutputXMLasNVARCHAR TINYINT = 0 ,
    @Version INT = NULL ,
    @VersionDate DATETIME = NULL
 

BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;


SELECT @Version = 9, @VersionDate = '20131103'

DECLARE @StringToExecute NVARCHAR(4000),
@OurSessionID INT,
@LineFeed NVARCHAR(10),
@StockWarningHeader NVARCHAR(500),
@StockWarningFooter NVARCHAR(100),
@StockDetailsHeader NVARCHAR(100),
@StockDetailsFooter NVARCHAR(100),
@StartSampleTime DATETIME,
@FinishSampleTime DATETIME;

/* Sanitize our inputs */
SELECT
@OutputDatabaseName = QUOTENAME(@OutputDatabaseName),
@OutputSchemaName = QUOTENAME(@OutputSchemaName),
@OutputTableName = QUOTENAME(@OutputTableName),
@LineFeed = CHAR(13) + CHAR(10),
@StartSampleTime = GETDATE(),
@FinishSampleTime = DATEADD(ss, @Seconds, GETDATE()),
@OurSessionID = @@SPID;

IF @OutputType = 'SCHEMA'
BEGIN
SELECT @Version AS Version,
FieldList = '[Priority] TINYINT, [FindingsGroup] VARCHAR(50), [Finding] VARCHAR(200), [URL] VARCHAR(200), [Details] NVARCHAR(4000), [HowToStopIt] NVARCHAR(MAX), [QueryPlan] XML, [QueryText] NVARCHAR(MAX)'

END
ELSE IF @AsOf IS NOT NULL AND @OutputDatabaseName IS NOT NULL AND @OutputSchemaName IS NOT NULL AND @OutputTableName IS NOT NULL
BEGIN
/* They want to look into the past. */

SET @StringToExecute = N' IF EXISTS(SELECT * FROM '
+ @OutputDatabaseName
+ '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
+ @OutputSchemaName + ''') SELECT CheckDate, [Priority], [FindingsGroup], [Finding], [URL], CAST([Details] AS [XML]) AS Details,'
+ '[HowToStopIt], [CheckID], [StartTime], [LoginName], [NTUserName], [OriginalLoginName], [ProgramName], [HostName], [DatabaseID],'
+ '[DatabaseName], [OpenTransactionCount], [QueryPlan], [QueryText] FROM '
+ @OutputDatabaseName + '.'
+ @OutputSchemaName + '.'
+ @OutputTableName
+ ' WHERE CheckDate >= DATEADD(mi, -15, ''' + CAST(@AsOf AS NVARCHAR(100)) + ''')'
+ ' AND CheckDate <= DATEADD(mi, 15, ''' + CAST(@AsOf AS NVARCHAR(100)) + ''')'
+ ' /*ORDER BY CheckDate, Priority , FindingsGroup , Finding , Details*/;';
EXEC(@StringToExecute);


END /* IF @AsOf IS NOT NULL AND @OutputDatabaseName IS NOT NULL AND @OutputSchemaName IS NOT NULL AND @OutputTableName IS NOT NULL */
ELSE IF @Question IS NULL /* IF @OutputType = 'SCHEMA' */
BEGIN

IF OBJECT_ID('tempdb..#AnalysisResults') IS NOT NULL
DROP TABLE #AnalysisResults;
CREATE TABLE #AnalysisResults
(
 ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
 CheckID INT NOT NULL,
 Priority TINYINT NOT NULL,
 FindingsGroup VARCHAR(50) NOT NULL,
 Finding VARCHAR(200) NOT NULL,
 URL VARCHAR(200) NOT NULL,
 Details NVARCHAR(4000) NULL,
 HowToStopIt [XML] NULL,
 QueryPlan [XML] NULL,
 QueryText NVARCHAR(MAX) NULL,
 StartTime DATETIME NULL,
 LoginName NVARCHAR(128) NULL,
 NTUserName NVARCHAR(128) NULL,
 OriginalLoginName NVARCHAR(128) NULL,
 ProgramName NVARCHAR(128) NULL,
 HostName NVARCHAR(128) NULL,
 DatabaseID INT NULL,
 DatabaseName NVARCHAR(128) NULL,
 OpenTransactionCount INT NULL
);

IF OBJECT_ID('tempdb..#WaitStats') IS NOT NULL
DROP TABLE #WaitStats;
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);

IF OBJECT_ID('tempdb..#FileStats') IS NOT NULL
DROP TABLE #FileStats;
CREATE TABLE #FileStats (
ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
Pass TINYINT NOT NULL,
SampleTime DATETIME NOT NULL,
DatabaseID INT NOT NULL,
FileID INT NOT NULL,
DatabaseName NVARCHAR(256) ,
FileLogicalName NVARCHAR(256) ,
TypeDesc NVARCHAR(60) ,
SizeOnDiskMB BIGINT ,
io_stall_read_ms BIGINT ,
num_of_reads BIGINT ,
bytes_read BIGINT ,
io_stall_write_ms BIGINT ,
num_of_writes BIGINT ,
bytes_written BIGINT,
PhysicalName NVARCHAR(520) ,
avg_stall_read_ms INT ,
avg_stall_write_ms INT
);

IF OBJECT_ID('tempdb..#QueryStats') IS NOT NULL
DROP TABLE #QueryStats;
CREATE TABLE #QueryStats (
ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
Pass TINYINT NOT NULL,
SampleTime DATETIME NOT NULL,
[sql_handle] VARBINARY(64),
statement_start_offset INT,
statement_end_offset INT,
plan_generation_num BIGINT,
plan_handle VARBINARY(64),
execution_count BIGINT,
total_worker_time BIGINT,
total_physical_reads BIGINT,
total_logical_writes BIGINT,
total_logical_reads BIGINT,
total_clr_time BIGINT,
total_elapsed_time BIGINT,
creation_time DATETIME,
query_hash BINARY(8),
query_plan_hash BINARY(8),
Points TINYINT
);

IF OBJECT_ID('tempdb..#PerfmonStats') IS NOT NULL
DROP TABLE #PerfmonStats;
CREATE TABLE #PerfmonStats (
ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
Pass TINYINT NOT NULL,
SampleTime DATETIME NOT NULL,
[object_name] NVARCHAR(128) NOT NULL,
[counter_name] NVARCHAR(128) NOT NULL,
[instance_name] NVARCHAR(128) NULL,
[cntr_value] BIGINT NULL,
[cntr_type] INT NOT NULL,
[value_delta] BIGINT NULL,
[value_per_second] DECIMAL(18,2) NULL
);

IF OBJECT_ID('tempdb..#PerfmonCounters') IS NOT NULL
DROP TABLE #PerfmonCounters;
CREATE TABLE #PerfmonCounters (
ID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
[object_name] NVARCHAR(128) NOT NULL,
[counter_name] NVARCHAR(128) NOT NULL,
[instance_name] NVARCHAR(128) NULL
);

SET @StockWarningHeader = '<?ClickToSeeCommmand -- ' + @LineFeed + @LineFeed
+ 'WARNING: Running this command may result in data loss or an outage.' + @LineFeed
+ 'This tool is meant as a shortcut to help generate scripts for DBAs.' + @LineFeed
+ 'It is not a substitute for database training and experience.' + @LineFeed
+ 'Now, having said that, here''s the details:' + @LineFeed + @LineFeed;

SELECT @StockWarningFooter = @LineFeed + @LineFeed + '-- ?>',
@StockDetailsHeader = '<?ClickToSeeDetails -- ' + @LineFeed,
@StockDetailsFooter = @LineFeed + ' -- ?>';


/* Populate #QueryStats. SQL 2005 doesn't have query hash or query plan hash. */
IF @@VERSION LIKE 'Microsoft SQL Server 2005%'
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)
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
FROM sys.dm_exec_query_stats qs
WHERE qs.last_execution_time >= (DATEADD(ss, -10, GETDATE()));';
ELSE
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)
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
FROM sys.dm_exec_query_stats qs
WHERE qs.last_execution_time >= (DATEADD(ss, -10, GETDATE()));';
EXEC(@StringToExecute);

IF EXISTS (SELECT *
FROM tempdb.sys.all_objects obj
INNER JOIN tempdb.sys.all_columns col1 ON obj.object_id = col1.object_id AND col1.name = 'object_name'
INNER JOIN tempdb.sys.all_columns col2 ON obj.object_id = col2.object_id AND col2.name = 'counter_name'
INNER JOIN tempdb.sys.all_columns col3 ON obj.object_id = col3.object_id AND col3.name = 'instance_name'
WHERE obj.name LIKE '%CustomPerfmonCounters%')
BEGIN
SET @StringToExecute = 'INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) SELECT [object_name],[counter_name],[instance_name] FROM #CustomPerfmonCounters'
EXEC(@StringToExecute);
END
ELSE
BEGIN
/* Add our default Perfmon counters */
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Forwarded Records/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Page compression attempts/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Page Splits/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Skipped Ghosted Records/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Table Lock Escalations/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Access Methods','Worktables Created/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Page life expectancy', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Page reads/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Page writes/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Readahead pages/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Target pages', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Total pages', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Databases','', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Buffer Manager','Active Transactions','_Total')
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Databases','Log Growths', '_Total')
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Databases','Log Shrinks', '_Total')
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Exec Statistics','Distributed Query', 'Execs in progress')
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Exec Statistics','DTC calls', 'Execs in progress')
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Exec Statistics','Extended Procedures', 'Execs in progress')
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Exec Statistics','OLEDB calls', 'Execs in progress')
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:General Statistics','Active Temp Tables', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:General Statistics','Logins/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:General Statistics','Logouts/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:General Statistics','Mars Deadlocks', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:General Statistics','Processes blocked', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Locks','Number of Deadlocks/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:Memory Manager','Memory Grants Pending', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Errors','Errors/sec', '_Total')
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','Batch Requests/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','Forced Parameterizations/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','Guided plan executions/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','SQL Attention rate', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','SQL Compilations/sec', NULL)
INSERT INTO #PerfmonCounters ([object_name],[counter_name],[instance_name]) VALUES ('SQLServer:SQL Statistics','SQL Re-Compilations/sec', NULL)
END

/* Populate #FileStats, #PerfmonStats, #WaitStats with DMV data.
After we finish doing our checks, we'll take another sample and compare them. */
INSERT #WaitStats(Pass, SampleTime, wait_type, wait_time_ms, signal_wait_time_ms, waiting_tasks_count)
SELECT
1 AS Pass,
GETDATE() AS SampleTime,
os.wait_type,
SUM(os.wait_time_ms) OVER (PARTITION BY os.wait_type) as sum_wait_time_ms,
SUM(os.signal_wait_time_ms) OVER (PARTITION BY os.wait_type ) as sum_signal_wait_time_ms,
SUM(os.waiting_tasks_count) OVER (PARTITION BY os.wait_type) AS sum_waiting_tasks
FROM sys.dm_os_wait_stats os
WHERE
os.wait_type not in (
'REQUEST_FOR_DEADLOCK_SEARCH',
'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
'SQLTRACE_BUFFER_FLUSH',
'LAZYWRITER_SLEEP',
'XE_TIMER_EVENT',
'XE_DISPATCHER_WAIT',
'FT_IFTS_SCHEDULER_IDLE_WAIT',
'LOGMGR_QUEUE',
'CHECKPOINT_QUEUE',
'BROKER_TO_FLUSH',
'BROKER_TASK_STOP',
'BROKER_EVENTHANDLER',
'SLEEP_TASK',
'WAITFOR',
'DBMIRROR_DBM_MUTEX',
'DBMIRROR_EVENTS_QUEUE',
'DBMIRRORING_CMD',
'DISPATCHER_QUEUE_SEMAPHORE',
'BROKER_RECEIVE_WAITFOR',
'CLR_AUTO_EVENT',
'DIRTY_PAGE_POLL',
'HADR_FILESTREAM_IOMGR_IOCOMPLETION',
'ONDEMAND_TASK_QUEUE',
'FT_IFTSHC_MUTEX',
'CLR_MANUAL_EVENT',
'SP_SERVER_DIAGNOSTICS_SLEEP',
'HADR_CLUSAPI_CALL',
'HADR_LOGCAPTURE_WAIT',
'HADR_TIMER_TASK',
'HADR_WORK_QUEUE'
)
ORDER BY sum_wait_time_ms DESC;


INSERT INTO #FileStats (Pass, SampleTime, DatabaseID, FileID, DatabaseName, FileLogicalName, SizeOnDiskMB, io_stall_read_ms ,
num_of_reads, [bytes_read] , io_stall_write_ms,num_of_writes, [bytes_written], PhysicalName, TypeDesc)
SELECT
1 AS Pass,
GETDATE() AS SampleTime,
mf.[database_id],
mf.[file_id],
DB_NAME(vfs.database_id) AS [db_name],
mf.name + N' [' + mf.type_desc COLLATE SQL_Latin1_General_CP1_CI_AS + N']' AS file_logical_name ,
CAST(( ( vfs.size_on_disk_bytes / 1024.0 ) / 1024.0 ) AS INT) AS size_on_disk_mb ,
vfs.io_stall_read_ms ,
vfs.num_of_reads ,
vfs.[num_of_bytes_read],
vfs.io_stall_write_ms ,
vfs.num_of_writes ,
vfs.[num_of_bytes_written],
mf.physical_name,
mf.type_desc
FROM sys.dm_io_virtual_file_stats (NULL, NULL) AS vfs
INNER JOIN sys.master_files AS mf ON vfs.file_id = mf.file_id
AND vfs.database_id = mf.database_id
WHERE vfs.num_of_reads > 0
OR vfs.num_of_writes > 0;

INSERT INTO #PerfmonStats (Pass, SampleTime, [object_name],[counter_name],[instance_name],[cntr_value],[cntr_type])
SELECT 1 AS Pass,
GETDATE() AS SampleTime, RTRIM(dmv.object_name), RTRIM(dmv.counter_name), RTRIM(dmv.instance_name), dmv.cntr_value, dmv.cntr_type
FROM #PerfmonCounters counters
INNER JOIN sys.dm_os_performance_counters dmv ON counters.counter_name = RTRIM(dmv.counter_name)
AND counters.[object_name] = RTRIM(dmv.[object_name])
AND (counters.[instance_name] IS NULL OR counters.[instance_name] = RTRIM(dmv.[instance_name]))

/* Maintenance Tasks Running - Backup Running - CheckID 1 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
SELECT 1 AS CheckID,
1 AS Priority,
'Maintenance Tasks Running' AS FindingGroup,
'Backup Running' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'Backup of ' + DB_NAME(db.resource_database_id) + ' database (' + (SELECT CAST(CAST(SUM(size * 8.0 / 1024 / 1024) AS BIGINT) AS NVARCHAR) FROM sys.master_files WHERE database_id = db.resource_database_id) + 'GB) is ' + CAST(r.percent_complete AS NVARCHAR(100)) + '% complete, has been running since ' + CAST(r.start_time AS NVARCHAR(100)) + '. ' AS Details,
CAST(@StockWarningHeader + 'KILL ' + CAST(r.session_id AS NVARCHAR(100)) + ';' + @StockWarningFooter AS XML) AS HowToStopIt,
pl.query_plan AS QueryPlan,
r.start_time AS StartTime,
s.login_name AS LoginName,
s.nt_user_name AS NTUserName,
s.[program_name] AS ProgramName,
s.[host_name] AS HostName,
db.[resource_database_id] AS DatabaseID,
DB_NAME(db.resource_database_id) AS DatabaseName,
0 AS OpenTransactionCount
FROM sys.dm_exec_requests r
INNER JOIN sys.dm_exec_connections c ON r.session_id = c.session_id
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
INNER JOIN (
SELECT DISTINCT request_session_id, resource_database_id
FROM    sys.dm_tran_locks
WHERE resource_type = N'DATABASE'
AND     request_mode = N'S'
AND     request_status = N'GRANT'
AND     request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
WHERE r.command LIKE 'BACKUP%';


/* If there's a backup running, add details explaining how long full backup has been taking in the last month. */
UPDATE #AnalysisResults
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 #AnalysisResults 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)



/* Maintenance Tasks Running - DBCC Running - CheckID 2 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
SELECT 2 AS CheckID,
1 AS Priority,
'Maintenance Tasks Running' AS FindingGroup,
'DBCC Running' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'Corruption check of ' + DB_NAME(db.resource_database_id) + ' database (' + (SELECT CAST(CAST(SUM(size * 8.0 / 1024 / 1024) AS BIGINT) AS NVARCHAR) FROM sys.master_files WHERE database_id = db.resource_database_id) + 'GB) has been running since ' + CAST(r.start_time AS NVARCHAR(100)) + '. ' AS Details,
CAST(@StockWarningHeader + 'KILL ' + CAST(r.session_id AS NVARCHAR(100)) + ';' + @StockWarningFooter AS XML) AS HowToStopIt,
pl.query_plan AS QueryPlan,
r.start_time AS StartTime,
s.login_name AS LoginName,
s.nt_user_name AS NTUserName,
s.[program_name] AS ProgramName,
s.[host_name] AS HostName,
db.[resource_database_id] AS DatabaseID,
DB_NAME(db.resource_database_id) AS DatabaseName,
0 AS OpenTransactionCount
FROM sys.dm_exec_requests r
INNER JOIN sys.dm_exec_connections c ON r.session_id = c.session_id
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
INNER JOIN (SELECT DISTINCT l.request_session_id, l.resource_database_id
FROM    sys.dm_tran_locks l
INNER JOIN sys.databases d ON l.resource_database_id = d.database_id
WHERE l.resource_type = N'DATABASE'
AND     l.request_mode = N'S'
AND    l.request_status = N'GRANT'
AND    l.request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
WHERE r.command LIKE 'DBCC%';


/* Maintenance Tasks Running - Restore Running - CheckID 3 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
SELECT 3 AS CheckID,
1 AS Priority,
'Maintenance Tasks Running' AS FindingGroup,
'Restore Running' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'Restore of ' + DB_NAME(db.resource_database_id) + ' database (' + (SELECT CAST(CAST(SUM(size * 8.0 / 1024 / 1024) AS BIGINT) AS NVARCHAR) FROM sys.master_files WHERE database_id = db.resource_database_id) + 'GB) is ' + CAST(r.percent_complete AS NVARCHAR(100)) + '% complete, has been running since ' + CAST(r.start_time AS NVARCHAR(100)) + '. ' AS Details,
CAST(@StockWarningHeader + 'KILL ' + CAST(r.session_id AS NVARCHAR(100)) + ';' + @StockWarningFooter AS XML) AS HowToStopIt,
pl.query_plan AS QueryPlan,
r.start_time AS StartTime,
s.login_name AS LoginName,
s.nt_user_name AS NTUserName,
s.[program_name] AS ProgramName,
s.[host_name] AS HostName,
db.[resource_database_id] AS DatabaseID,
DB_NAME(db.resource_database_id) AS DatabaseName,
0 AS OpenTransactionCount
FROM sys.dm_exec_requests r
INNER JOIN sys.dm_exec_connections c ON r.session_id = c.session_id
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
INNER JOIN (
SELECT DISTINCT request_session_id, resource_database_id
FROM    sys.dm_tran_locks
WHERE resource_type = N'DATABASE'
AND     request_mode = N'S'
AND     request_status = N'GRANT'
AND     request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
WHERE r.command LIKE 'RESTORE%';


/* SQL Server Internal Maintenance - Database File Growing - CheckID 4 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
SELECT 4 AS CheckID,
1 AS Priority,
'SQL Server Internal Maintenance' AS FindingGroup,
'Database File Growing' AS Finding,
' ' AS URL,
@StockDetailsHeader + '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,
CAST(@StockWarningHeader + 'Unfortunately, you can''t stop this, but you can prevent it next time. Check out  for details.' + @StockWarningFooter AS XML) AS HowToStopIt,
pl.query_plan AS QueryPlan,
r.start_time AS StartTime,
s.login_name AS LoginName,
s.nt_user_name AS NTUserName,
s.[program_name] AS ProgramName,
s.[host_name] AS HostName,
NULL AS DatabaseID,
NULL AS DatabaseName,
0 AS OpenTransactionCount
FROM sys.dm_os_waiting_tasks t
INNER JOIN sys.dm_exec_connections c ON t.session_id = c.session_id
INNER JOIN sys.dm_exec_requests r ON t.session_id = r.session_id
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl
WHERE t.wait_type = 'PREEMPTIVE_OS_WRITEFILEGATHER'


/* Query Problems - Long-Running Query Blocking Others - CheckID 5 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount)
SELECT 5 AS CheckID,
1 AS Priority,
'Query Problems' AS FindingGroup,
'Long-Running Query Blocking Others' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'Query in ' + DB_NAME(db.resource_database_id) + ' has been running since ' + CAST(r.start_time AS NVARCHAR(100)) + '. ' + @LineFeed + @LineFeed
+ CAST(COALESCE((SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(rBlocker.sql_handle)),
(SELECT TOP 1 [text] FROM master..sysprocesses spBlocker CROSS APPLY ::fn_get_sql(spBlocker.sql_handle) WHERE spBlocker.spid = tBlocked.blocking_session_id), '') AS NVARCHAR(2000)) AS Details,
CAST(@StockWarningHeader + 'KILL ' + CAST(tBlocked.blocking_session_id AS NVARCHAR(100)) + ';' + @StockWarningFooter AS XML) AS HowToStopIt,
(SELECT TOP 1 query_plan FROM sys.dm_exec_query_plan(rBlocker.plan_handle)) AS QueryPlan,
COALESCE((SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(rBlocker.sql_handle)),
(SELECT TOP 1 [text] FROM master..sysprocesses spBlocker CROSS APPLY ::fn_get_sql(spBlocker.sql_handle) WHERE spBlocker.spid = tBlocked.blocking_session_id)) AS QueryText,
r.start_time AS StartTime,
s.login_name AS LoginName,
s.nt_user_name AS NTUserName,
s.[program_name] AS ProgramName,
s.[host_name] AS HostName,
db.[resource_database_id] AS DatabaseID,
DB_NAME(db.resource_database_id) AS DatabaseName,
0 AS OpenTransactionCount
FROM sys.dm_exec_sessions s
INNER JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
INNER JOIN sys.dm_os_waiting_tasks tBlocked ON tBlocked.session_id = s.session_id AND tBlocked.session_id <> s.session_id
INNER JOIN (
SELECT DISTINCT request_session_id, resource_database_id
FROM    sys.dm_tran_locks
WHERE resource_type = N'DATABASE'
AND     request_mode = N'S'
AND     request_status = N'GRANT'
AND     request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
LEFT OUTER JOIN sys.dm_exec_requests rBlocker ON tBlocked.blocking_session_id = rBlocker.session_id
 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)
 AND s.last_request_start_time < DATEADD(SECOND, -30, GETDATE())

/* Query Problems - Plan Cache Erased Recently */
IF DATEADD(mi, -15, GETDATE()) < (SELECT TOP 1 creation_time FROM sys.dm_exec_query_stats ORDER BY creation_time)
BEGIN
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
SELECT TOP 1 7 AS CheckID,
50 AS Priority,
'Query Problems' AS FindingGroup,
'Plan Cache Erased Recently' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'The oldest query in the plan cache was created at ' + CAST(creation_time AS NVARCHAR(50)) + '. ' + @LineFeed + @LineFeed
+ 'This indicates that someone ran DBCC FREEPROCCACHE at that time,' + @LineFeed
+ 'Giving SQL Server temporary amnesia. Now, as queries come in,' + @LineFeed
+ 'SQL Server has to use a lot of CPU power in order to build execution' + @LineFeed
+ 'plans and put them in cache again. This causes high CPU loads.' AS Details,
CAST(@StockWarningHeader + 'Find who did that, and stop them from doing it again.' + @StockWarningFooter AS XML) AS HowToStopIt
FROM sys.dm_exec_query_stats
ORDER BY creation_time
END;


/* Query Problems - Sleeping Query with Open Transactions - CheckID 8 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, QueryText, OpenTransactionCount)
SELECT 8 AS CheckID,
50 AS Priority,
'Query Problems' AS FindingGroup,
'Sleeping Query with Open Transactions' AS Finding,
' ' AS URL,
@StockDetailsHeader + '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,
CAST(@StockWarningHeader + 'KILL ' + CAST(s.session_id AS NVARCHAR(100)) + ';' + @StockWarningFooter AS XML) AS HowToStopIt,
s.last_request_start_time AS StartTime,
s.login_name AS LoginName,
s.nt_user_name AS NTUserName,
s.[program_name] AS ProgramName,
s.[host_name] AS HostName,
db.[resource_database_id] AS DatabaseID,
DB_NAME(db.resource_database_id) AS DatabaseName,
(SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(c.most_recent_sql_handle)) AS QueryText,
sessions_with_transactions.open_transaction_count AS OpenTransactionCount
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
INNER JOIN sys.dm_exec_sessions s ON sessions_with_transactions.session_id = s.session_id
INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
INNER JOIN (
SELECT DISTINCT request_session_id, resource_database_id
FROM    sys.dm_tran_locks
WHERE resource_type = N'DATABASE'
AND     request_mode = N'S'
AND     request_status = N'GRANT'
AND     request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
WHERE s.status = 'sleeping'
AND s.last_request_end_time < DATEADD(ss, -10, GETDATE())
AND EXISTS(SELECT * FROM sys.dm_tran_locks WHERE request_session_id = s.session_id
AND NOT (resource_type = N'DATABASE' AND request_mode = N'S' AND request_status = N'GRANT' AND request_owner_type = N'SHARED_TRANSACTION_WORKSPACE'))


/* Query Problems - Query Rolling Back - CheckID 9 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, StartTime, LoginName, NTUserName, ProgramName, HostName, DatabaseID, DatabaseName, QueryText)
SELECT 9 AS CheckID,
1 AS Priority,
'Query Problems' AS FindingGroup,
'Query Rolling Back' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'Rollback started at ' + CAST(r.start_time AS NVARCHAR(100)) + ', is ' + CAST(r.percent_complete AS NVARCHAR(100)) + '% complete.' AS Details,
CAST(@StockWarningHeader + '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.' + @StockWarningFooter AS XML) AS HowToStopIt,
r.start_time AS StartTime,
s.login_name AS LoginName,
s.nt_user_name AS NTUserName,
s.[program_name] AS ProgramName,
s.[host_name] AS HostName,
db.[resource_database_id] AS DatabaseID,
DB_NAME(db.resource_database_id) AS DatabaseName,
(SELECT TOP 1 [text] FROM sys.dm_exec_sql_text(c.most_recent_sql_handle)) AS QueryText
FROM sys.dm_exec_sessions s
INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
INNER JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
LEFT OUTER JOIN (
SELECT DISTINCT request_session_id, resource_database_id
FROM    sys.dm_tran_locks
WHERE resource_type = N'DATABASE'
AND     request_mode = N'S'
AND     request_status = N'GRANT'
AND     request_owner_type = N'SHARED_TRANSACTION_WORKSPACE') AS db ON s.session_id = db.request_session_id
WHERE r.status = 'rollback'


/* Server Performance - Page Life Expectancy Low - CheckID 10 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
SELECT 10 AS CheckID,
50 AS Priority,
'Server Performance' AS FindingGroup,
'Page Life Expectancy Low' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'SQL Server Buffer Manager:Page life expectancy is ' + CAST(c.cntr_value AS NVARCHAR(10)) + ' seconds.' + @LineFeed
+ 'This means SQL Server can only keep data pages in memory for that many seconds after reading those pages in from storage.' + @LineFeed
+ 'This is a symptom, not a cause - it indicates very read-intensive queries that need an index, or insufficient server memory.' AS Details,
CAST(@StockWarningHeader + '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).' + @StockWarningFooter AS XML) AS HowToStopIt
FROM sys.dm_os_performance_counters c
WHERE object_name LIKE 'SQLServer:Buffer Manager%'
AND counter_name LIKE 'Page life expectancy%'
AND cntr_value < 300



/* End of checks. If we haven't waited @Seconds seconds, wait. */
IF GETDATE() < @FinishSampleTime
WAITFOR TIME @FinishSampleTime;


/* Populate #FileStats, #PerfmonStats, #WaitStats with DMV data. In a second, we'll compare these. */
INSERT #WaitStats(Pass, SampleTime, wait_type, wait_time_ms, signal_wait_time_ms, waiting_tasks_count)
SELECT
2 AS Pass,
GETDATE() AS SampleTime,
os.wait_type,
SUM(os.wait_time_ms) OVER (PARTITION BY os.wait_type) as sum_wait_time_ms,
SUM(os.signal_wait_time_ms) OVER (PARTITION BY os.wait_type ) as sum_signal_wait_time_ms,
SUM(os.waiting_tasks_count) OVER (PARTITION BY os.wait_type) AS sum_waiting_tasks
FROM sys.dm_os_wait_stats os
WHERE
os.wait_type not in (
'REQUEST_FOR_DEADLOCK_SEARCH',
'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
'SQLTRACE_BUFFER_FLUSH',
'LAZYWRITER_SLEEP',
'XE_TIMER_EVENT',
'XE_DISPATCHER_WAIT',
'FT_IFTS_SCHEDULER_IDLE_WAIT',
'LOGMGR_QUEUE',
'CHECKPOINT_QUEUE',
'BROKER_TO_FLUSH',
'BROKER_TASK_STOP',
'BROKER_EVENTHANDLER',
'SLEEP_TASK',
'WAITFOR',
'DBMIRROR_DBM_MUTEX',
'DBMIRROR_EVENTS_QUEUE',
'DBMIRRORING_CMD',
'DISPATCHER_QUEUE_SEMAPHORE',
'BROKER_RECEIVE_WAITFOR',
'CLR_AUTO_EVENT',
'DIRTY_PAGE_POLL',
'HADR_FILESTREAM_IOMGR_IOCOMPLETION',
'ONDEMAND_TASK_QUEUE',
'FT_IFTSHC_MUTEX',
'CLR_MANUAL_EVENT',
'SP_SERVER_DIAGNOSTICS_SLEEP',
'HADR_CLUSAPI_CALL',
'HADR_LOGCAPTURE_WAIT',
'HADR_TIMER_TASK',
'HADR_WORK_QUEUE'
)
ORDER BY sum_wait_time_ms DESC;

INSERT INTO #FileStats (Pass, SampleTime, DatabaseID, FileID, DatabaseName, FileLogicalName, SizeOnDiskMB, io_stall_read_ms ,
num_of_reads, [bytes_read] , io_stall_write_ms,num_of_writes, [bytes_written], PhysicalName, TypeDesc, avg_stall_read_ms, avg_stall_write_ms)
SELECT 2 AS Pass,
GETDATE() AS SampleTime,
mf.[database_id],
mf.[file_id],
DB_NAME(vfs.database_id) AS [db_name],
mf.name + N' [' + mf.type_desc COLLATE SQL_Latin1_General_CP1_CI_AS + N']' AS file_logical_name ,
CAST(( ( vfs.size_on_disk_bytes / 1024.0 ) / 1024.0 ) AS INT) AS size_on_disk_mb ,
vfs.io_stall_read_ms ,
vfs.num_of_reads ,
vfs.[num_of_bytes_read],
vfs.io_stall_write_ms ,
vfs.num_of_writes ,
vfs.[num_of_bytes_written],
mf.physical_name,
mf.type_desc,
0,
0
FROM sys.dm_io_virtual_file_stats (NULL, NULL) AS vfs
INNER JOIN sys.master_files AS mf ON vfs.file_id = mf.file_id
AND vfs.database_id = mf.database_id
WHERE vfs.num_of_reads > 0
OR vfs.num_of_writes > 0;

INSERT INTO #PerfmonStats (Pass, SampleTime, [object_name],[counter_name],[instance_name],[cntr_value],[cntr_type])
SELECT 2 AS Pass,
GETDATE() AS SampleTime,
RTRIM(dmv.object_name), RTRIM(dmv.counter_name), RTRIM(dmv.instance_name), dmv.cntr_value, dmv.cntr_type
FROM #PerfmonCounters counters
INNER JOIN sys.dm_os_performance_counters dmv ON counters.counter_name = RTRIM(dmv.counter_name)
AND counters.[object_name] = RTRIM(dmv.[object_name])
AND (counters.[instance_name] IS NULL OR counters.[instance_name] = RTRIM(dmv.[instance_name]))

/* Set the latencies and averages. We could do this with a CTE, but we're not ambitious today. */
UPDATE fNow
SET avg_stall_read_ms = ((fNow.io_stall_read_ms - fBase.io_stall_read_ms) / (fNow.num_of_reads - fBase.num_of_reads))
FROM #FileStats fNow
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
WHERE (fNow.num_of_reads - fBase.num_of_reads) > 0

UPDATE fNow
SET avg_stall_write_ms = ((fNow.io_stall_write_ms - fBase.io_stall_write_ms) / (fNow.num_of_writes - fBase.num_of_writes))
FROM #FileStats fNow
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
WHERE (fNow.num_of_writes - fBase.num_of_writes) > 0

UPDATE pNow
SET [value_delta] = pNow.cntr_value - pFirst.cntr_value,
[value_per_second] = ((1.0 * pNow.cntr_value - pFirst.cntr_value) / DATEDIFF(ss, pFirst.SampleTime, pNow.SampleTime))
FROM #PerfmonStats pNow
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))
AND pNow.ID > pFirst.ID;


/* If we're within 10 seconds of our projected finish time, do the plan cache analysis. */
IF DATEDIFF(ss, @FinishSampleTime, GETDATE()) > 10 AND @ExpertMode = 0
BEGIN

INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
VALUES (18, 210, 'Query Stats', 'Plan Cache Analysis Skipped', ' ',
@StockDetailsHeader + 'Due to excessive load, the plan cache analysis was skipped. To override this, use @ExpertMode = 1.')

END
ELSE /* IF DATEDIFF(ss, @FinishSampleTime, GETDATE()) > 10 AND @ExpertMode = 0 */
BEGIN


/* Populate #QueryStats. SQL 2005 doesn't have query hash or query plan hash. */
IF @@VERSION LIKE 'Microsoft SQL Server 2005%'
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)
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
FROM sys.dm_exec_query_stats qs
WHERE qs.last_execution_time >= ''' + CAST(@StartSampleTime AS NVARCHAR(100)) + ''';';
ELSE
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)
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
FROM sys.dm_exec_query_stats qs
WHERE qs.last_execution_time >= ''' + CAST(@StartSampleTime AS NVARCHAR(100)) + ''';';
EXEC(@StringToExecute);

/* Get the totals for the entire plan cache */
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)
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)
FROM sys.dm_exec_query_stats qs;

/*
Pick the most resource-intensive queries to review. Update the Points field
in #QueryStats - if a query is in the top 10 for logical reads, CPU time,
duration, or execution, add 1 to its points.
*/
WITH qsTop AS (
SELECT TOP 10 qsNow.ID
FROM #QueryStats qsNow
 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
WHERE qsNow.total_elapsed_time > qsFirst.total_elapsed_time
AND qsNow.Pass = 2
ORDER BY (qsNow.total_elapsed_time - COALESCE(qsFirst.total_elapsed_time, 0)) DESC)
UPDATE #QueryStats
SET Points = Points + 1
FROM #QueryStats qs
INNER JOIN qsTop ON qs.ID = qsTop.ID;

WITH qsTop AS (
SELECT TOP 10 qsNow.ID
FROM #QueryStats qsNow
 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
WHERE qsNow.total_logical_reads > qsFirst.total_logical_reads
AND qsNow.Pass = 2
ORDER BY (qsNow.total_logical_reads - COALESCE(qsFirst.total_logical_reads, 0)) DESC)
UPDATE #QueryStats
SET Points = Points + 1
FROM #QueryStats qs
INNER JOIN qsTop ON qs.ID = qsTop.ID;

WITH qsTop AS (
SELECT TOP 10 qsNow.ID
FROM #QueryStats qsNow
 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
WHERE qsNow.total_worker_time > qsFirst.total_worker_time
AND qsNow.Pass = 2
ORDER BY (qsNow.total_worker_time - COALESCE(qsFirst.total_worker_time, 0)) DESC)
UPDATE #QueryStats
SET Points = Points + 1
FROM #QueryStats qs
INNER JOIN qsTop ON qs.ID = qsTop.ID;

WITH qsTop AS (
SELECT TOP 10 qsNow.ID
FROM #QueryStats qsNow
 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
WHERE qsNow.execution_count > qsFirst.execution_count
AND qsNow.Pass = 2
ORDER BY (qsNow.execution_count - COALESCE(qsFirst.execution_count, 0)) DESC)
UPDATE #QueryStats
SET Points = Points + 1
FROM #QueryStats qs
INNER JOIN qsTop ON qs.ID = qsTop.ID;

/* Query Stats - CheckID 17 - Most Resource-Intensive Queries */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText)
SELECT 17, 210, 'Query Stats', 'Most Resource-Intensive Queries', ' ',
@StockDetailsHeader + 'Query stats during the sample:' + @LineFeed +
'Executions: ' + CAST(qsNow.execution_count - (COALESCE(qsFirst.execution_count, 0)) AS NVARCHAR(100)) + @LineFeed +
'Elapsed Time: ' + CAST(qsNow.total_elapsed_time - (COALESCE(qsFirst.total_elapsed_time, 0)) AS NVARCHAR(100)) + @LineFeed +
'CPU Time: ' + CAST(qsNow.total_worker_time - (COALESCE(qsFirst.total_worker_time, 0)) AS NVARCHAR(100)) + @LineFeed +
'Logical Reads: ' + CAST(qsNow.total_logical_reads - (COALESCE(qsFirst.total_logical_reads, 0)) AS NVARCHAR(100)) + @LineFeed +
'Logical Writes: ' + CAST(qsNow.total_logical_writes - (COALESCE(qsFirst.total_logical_writes, 0)) AS NVARCHAR(100)) + @LineFeed +
'CLR Time: ' + CAST(qsNow.total_clr_time - (COALESCE(qsFirst.total_clr_time, 0)) AS NVARCHAR(100)) + @LineFeed +
@LineFeed + @LineFeed + 'Query stats since ' + CONVERT(NVARCHAR(100), qsNow.creation_time ,121) + @LineFeed +
'Executions: ' + CAST(qsNow.execution_count AS NVARCHAR(100)) +
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 +
'Elapsed Time: ' + CAST(qsNow.total_elapsed_time AS NVARCHAR(100)) +
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 +
'CPU Time: ' + CAST(qsNow.total_worker_time AS NVARCHAR(100)) +
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 +
'Logical Reads: ' + CAST(qsNow.total_logical_reads AS NVARCHAR(100)) +
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 +
'Logical Writes: ' + CAST(qsNow.total_logical_writes AS NVARCHAR(100)) +
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 +
'CLR Time: ' + CAST(qsNow.total_clr_time AS NVARCHAR(100)) +
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 +
--@LineFeed + @LineFeed + 'Query hash: ' + CAST(qsNow.query_hash AS NVARCHAR(100)) + @LineFeed +
--@LineFeed + @LineFeed + 'Query plan hash: ' + CAST(qsNow.query_plan_hash AS NVARCHAR(100)) +
@LineFeed AS Details,
CAST(@StockWarningHeader + 'See the URL for tuning tips on why this query may be consuming resources.' + @StockWarningFooter AS XML) AS HowToStopIt,
qp.query_plan, st.text
FROM #QueryStats qsNow
INNER JOIN #QueryStats qsTotal ON qsTotal.Pass = 0
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
CROSS APPLY sys.dm_exec_sql_text(qsNow.sql_handle) AS st
CROSS APPLY sys.dm_exec_query_plan(qsNow.plan_handle) AS qp
WHERE qsNow.Points > 0 AND st.text IS NOT NULL AND qp.query_plan IS NOT NULL

END /* IF DATEDIFF(ss, @FinishSampleTime, GETDATE()) > 10 AND @ExpertMode = 0 */


/* Wait Stats - CheckID 6 */
/* Compare the current wait stats to the sample we took at the start, and insert the top 10 waits. */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
SELECT TOP 10 6 AS CheckID,
200 AS Priority,
'Wait Stats' AS FindingGroup,
wNow.wait_type AS Finding,
N' ' + wNow.wait_type AS URL,
@StockDetailsHeader + 'For ' + CAST(((wNow.wait_time_ms - COALESCE(wBase.wait_time_ms,0)) / 1000) AS NVARCHAR(100)) + ' seconds over the last ' + CAST(@Seconds AS NVARCHAR(10)) + ' seconds, SQL Server was waiting on this particular bottleneck.' + @LineFeed + @LineFeed AS Details,
CAST(@StockWarningHeader + 'See the URL for more details on how to mitigate this wait type.' + @StockWarningFooter AS XML) AS HowToStopIt
FROM #WaitStats wNow
LEFT OUTER JOIN #WaitStats wBase ON wNow.wait_type = wBase.wait_type AND wNow.SampleTime > wBase.SampleTime
WHERE wNow.wait_time_ms > (wBase.wait_time_ms + (.5 * @Seconds * 1000)) /* Only look for things we've actually waited on for half of the time or more */
AND wNow.wait_type NOT IN ('REQUEST_FOR_DEADLOCK_SEARCH','SQLTRACE_INCREMENTAL_FLUSH_SLEEP','SQLTRACE_BUFFER_FLUSH',
'LAZYWRITER_SLEEP','XE_TIMER_EVENT','XE_DISPATCHER_WAIT','FT_IFTS_SCHEDULER_IDLE_WAIT','LOGMGR_QUEUE','CHECKPOINT_QUEUE',
'BROKER_TO_FLUSH','BROKER_TASK_STOP','BROKER_EVENTHANDLER','BROKER_TRANSMITTER','SLEEP_TASK','WAITFOR','DBMIRROR_DBM_MUTEX',
'DBMIRROR_EVENTS_QUEUE','DBMIRRORING_CMD','DISPATCHER_QUEUE_SEMAPHORE','BROKER_RECEIVE_WAITFOR','CLR_AUTO_EVENT',
'DIRTY_PAGE_POLL','CLR_SEMAPHORE','HADR_FILESTREAM_IOMGR_IOCOMPLETION','ONDEMAND_TASK_QUEUE','FT_IFTSHC_MUTEX',
'CLR_MANUAL_EVENT','SP_SERVER_DIAGNOSTICS_SLEEP','DBMIRROR_WORKER_QUEUE','DBMIRROR_DBM_EVENT')
ORDER BY (wNow.wait_time_ms - COALESCE(wBase.wait_time_ms,0)) DESC;

/* Server Performance - Slow Data File Reads - CheckID 11 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, DatabaseID, DatabaseName)
SELECT TOP 10 11 AS CheckID,
50 AS Priority,
'Server Performance' AS FindingGroup,
'Slow Data File Reads' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'File: ' + fNow.PhysicalName + @LineFeed
+ 'Number of reads during the sample: ' + CAST((fNow.num_of_reads - fBase.num_of_reads) AS NVARCHAR(20)) + @LineFeed
+ '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
+ '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
+ 'Microsoft guidance for data file read speed: 20ms or less.' + @LineFeed + @LineFeed AS Details,
CAST(@StockWarningHeader + 'See the URL for more details on how to mitigate this wait type.' + @StockWarningFooter AS XML) AS HowToStopIt,
fNow.DatabaseID,
fNow.DatabaseName
FROM #FileStats fNow
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)
WHERE (fNow.io_stall_read_ms - fBase.io_stall_read_ms) / (fNow.num_of_reads - fBase.num_of_reads) > 100
AND fNow.TypeDesc = 'ROWS'
ORDER BY (fNow.io_stall_read_ms - fBase.io_stall_read_ms) / (fNow.num_of_reads - fBase.num_of_reads) DESC;

/* Server Performance - Slow Log File Writes - CheckID 12 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, DatabaseID, DatabaseName)
SELECT TOP 10 12 AS CheckID,
50 AS Priority,
'Server Performance' AS FindingGroup,
'Slow Log File Writes' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'File: ' + fNow.PhysicalName + @LineFeed
+ 'Number of writes during the sample: ' + CAST((fNow.num_of_writes - fBase.num_of_writes) AS NVARCHAR(20)) + @LineFeed
+ '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
+ '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
+ 'Microsoft guidance for log file write speed: 3ms or less.' + @LineFeed + @LineFeed AS Details,
CAST(@StockWarningHeader + 'See the URL for more details on how to mitigate this wait type.' + @StockWarningFooter AS XML) AS HowToStopIt,
fNow.DatabaseID,
fNow.DatabaseName
FROM #FileStats fNow
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)
WHERE (fNow.io_stall_write_ms - fBase.io_stall_write_ms) / (fNow.num_of_writes - fBase.num_of_writes) > 100
AND fNow.TypeDesc = 'LOG'
ORDER BY (fNow.io_stall_write_ms - fBase.io_stall_write_ms) / (fNow.num_of_writes - fBase.num_of_writes) DESC;


/* SQL Server Internal Maintenance - Log File Growing - CheckID 13 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
SELECT 13 AS CheckID,
1 AS Priority,
'SQL Server Internal Maintenance' AS FindingGroup,
'Log File Growing' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'Number of growths during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
+ 'Determined by sampling Perfmon counter ' + ps.object_name + ' - ' + ps.counter_name + @LineFeed AS Details,
CAST(@StockWarningHeader + 'Pre-grow data and log files during maintenance windows so that they do not grow during production loads.' + @StockWarningFooter AS XML) AS HowToStopIt
FROM #PerfmonStats ps
WHERE ps.Pass = 2
AND object_name = 'SQLServer:Databases'
AND counter_name = 'Log Growths'
AND value_delta > 0


/* SQL Server Internal Maintenance - Log File Shrinking - CheckID 14 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
SELECT 14 AS CheckID,
1 AS Priority,
'SQL Server Internal Maintenance' AS FindingGroup,
'Log File Shrinking' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'Number of shrinks during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
+ 'Determined by sampling Perfmon counter ' + ps.object_name + ' - ' + ps.counter_name + @LineFeed AS Details,
CAST(@StockWarningHeader + 'Pre-grow data and log files during maintenance windows so that they do not grow during production loads.' + @StockWarningFooter AS XML) AS HowToStopIt
FROM #PerfmonStats ps
WHERE ps.Pass = 2
AND object_name = 'SQLServer:Databases'
AND counter_name = 'Log Shrinks'
AND value_delta > 0

/* Query Problems - Compilations/Sec High - CheckID 15 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
SELECT 15 AS CheckID,
50 AS Priority,
'Query Problems' AS FindingGroup,
'Compilations/Sec High' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'Number of batch requests during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
+ 'Number of compilations during the sample: ' + CAST(psComp.value_delta AS NVARCHAR(20)) + @LineFeed
+ '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,
CAST(@StockWarningHeader + 'Find out why plans are not being reused, and consider enabling Forced Parameterization. See the URL for more details.' + @StockWarningFooter AS XML) AS HowToStopIt
FROM #PerfmonStats ps
INNER JOIN #PerfmonStats psComp ON psComp.Pass = 2 AND psComp.object_name = 'SQLServer:SQL Statistics' AND psComp.counter_name = 'SQL Compilations/sec' AND psComp.value_delta > 0
WHERE ps.Pass = 2
AND ps.object_name = 'SQLServer:SQL Statistics'
AND ps.counter_name = 'Batch Requests/sec'
AND ps.value_delta > 100 /* Ignore servers sitting idle */
AND (psComp.value_delta * 10) > ps.value_delta /* Compilations are more than 10% of batch requests per second */

/* Query Problems - Re-Compilations/Sec High - CheckID 16 */
INSERT INTO #AnalysisResults (CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt)
SELECT 16 AS CheckID,
50 AS Priority,
'Query Problems' AS FindingGroup,
'Re-Compilations/Sec High' AS Finding,
' ' AS URL,
@StockDetailsHeader + 'Number of batch requests during the sample: ' + CAST(ps.value_delta AS NVARCHAR(20)) + @LineFeed
+ 'Number of recompilations during the sample: ' + CAST(psComp.value_delta AS NVARCHAR(20)) + @LineFeed
+ 'More than 10% of our queries are being recompiled. This is typically due to statistics changing on objects.' + @LineFeed AS Details,
CAST(@StockWarningHeader + 'Find out which objects are changing so quickly that they hit the stats update threshold. See the URL for more details.' + @StockWarningFooter AS XML) AS HowToStopIt
FROM #PerfmonStats ps
INNER JOIN #PerfmonStats psComp ON psComp.Pass = 2 AND psComp.object_name = 'SQLServer:SQL Statistics' AND psComp.counter_name = 'SQL Re-Compilations/sec' AND psComp.value_delta > 0
WHERE ps.Pass = 2
AND ps.object_name = 'SQLServer:SQL Statistics'
AND ps.counter_name = 'Batch Requests/sec'
AND ps.value_delta > 100 /* Ignore servers sitting idle */
AND (psComp.value_delta * 10) > ps.value_delta /* Recompilations are more than 10% of batch requests per second */


/* If we didn't find anything, apologize. */
IF NOT EXISTS (SELECT * FROM #AnalysisResults)
BEGIN

INSERT  INTO #AnalysisResults
( CheckID ,
 Priority ,
 FindingsGroup ,
 Finding ,
 URL ,
 Details
)
VALUES  ( -1 , 255 , 'No Problems Found' , 'No Problems Found' , 'No Problems Found' ,
 @StockDetailsHeader + 'Try running our more in-depth checks:' + @LineFeed + 'or there may not be an unusual SQL Server performance problem. ' + @StockDetailsFooter
);

END /*IF NOT EXISTS (SELECT * FROM #AnalysisResults) */
ELSE /* We found stuff */
BEGIN
/* Close out the XML field Details by adding a footer */
UPDATE #AnalysisResults
 SET Details = Details + @StockDetailsFooter;

 
END /* ELSE  We found stuff */

/* @OutputTableName lets us export the results to a permanent table */
IF @OutputDatabaseName IS NOT NULL
AND @OutputSchemaName IS NOT NULL
AND @OutputTableName IS NOT NULL
AND EXISTS ( SELECT *
FROM   sys.databases
WHERE  QUOTENAME([name]) = @OutputDatabaseName)
BEGIN
SET @StringToExecute = 'USE '
+ @OutputDatabaseName
+ '; IF EXISTS(SELECT * FROM '
+ @OutputDatabaseName
+ '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
+ @OutputSchemaName
+ ''') AND NOT EXISTS (SELECT * FROM '
+ @OutputDatabaseName
+ '.INFORMATION_SCHEMA.TABLES WHERE QUOTENAME(TABLE_SCHEMA) = '''
+ @OutputSchemaName + ''' AND QUOTENAME(TABLE_NAME) = '''
+ @OutputTableName + ''') CREATE TABLE '
+ @OutputSchemaName + '.'
+ @OutputTableName
+ ' (ID INT IDENTITY(1,1) NOT NULL,
ServerName NVARCHAR(128),
CheckDate DATETIME,
AnalysisVersion INT,
CheckID INT NOT NULL,
Priority TINYINT NOT NULL,
FindingsGroup VARCHAR(50) NOT NULL,
Finding VARCHAR(200) NOT NULL,
URL VARCHAR(200) NOT NULL,
Details NVARCHAR(4000) NULL,
HowToStopIt [XML] NULL,
QueryPlan [XML] NULL,
QueryText NVARCHAR(MAX) NULL,
StartTime DATETIME NULL,
LoginName NVARCHAR(128) NULL,
NTUserName NVARCHAR(128) NULL,
OriginalLoginName NVARCHAR(128) NULL,
ProgramName NVARCHAR(128) NULL,
HostName NVARCHAR(128) NULL,
DatabaseID INT NULL,
DatabaseName NVARCHAR(128) NULL,
OpenTransactionCount INT NULL,
CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'

EXEC(@StringToExecute);
SET @StringToExecute = N' IF EXISTS(SELECT * FROM '
+ @OutputDatabaseName
+ '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = '''
+ @OutputSchemaName + ''') INSERT '
+ @OutputDatabaseName + '.'
+ @OutputSchemaName + '.'
+ @OutputTableName
+ ' (ServerName, CheckDate, AnalysisVersion, CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount) SELECT '''
+ CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
+ ''', GETDATE(), ' + CAST(@Version AS NVARCHAR(128))
+ ', CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount FROM #AnalysisResults ORDER BY Priority , FindingsGroup , Finding , Details';
EXEC(@StringToExecute);
END
ELSE IF (SUBSTRING(@OutputTableName, 2, 2) = '##')
BEGIN
SET @StringToExecute = N' IF (OBJECT_ID(''tempdb..'
+ @OutputTableName
+ ''') IS NOT NULL) DROP TABLE ' + @OutputTableName + ';'
+ 'CREATE TABLE '
+ @OutputTableName
+ ' (ID INT IDENTITY(1,1) NOT NULL,
ServerName NVARCHAR(128),
CheckDate DATETIME,
AnalysisVersion INT,
CheckID INT NOT NULL,
Priority TINYINT NOT NULL,
FindingsGroup VARCHAR(50) NOT NULL,
Finding VARCHAR(200) NOT NULL,
URL VARCHAR(200) NOT NULL,
Details NVARCHAR(4000) NULL,
HowToStopIt [XML] NULL,
QueryPlan [XML] NULL,
QueryText NVARCHAR(MAX) NULL,
StartTime DATETIME NULL,
LoginName NVARCHAR(128) NULL,
NTUserName NVARCHAR(128) NULL,
OriginalLoginName NVARCHAR(128) NULL,
ProgramName NVARCHAR(128) NULL,
HostName NVARCHAR(128) NULL,
DatabaseID INT NULL,
DatabaseName NVARCHAR(128) NULL,
OpenTransactionCount INT NULL,
CONSTRAINT [PK_' + CAST(NEWID() AS CHAR(36)) + '] PRIMARY KEY CLUSTERED (ID ASC));'
+ ' INSERT '
+ @OutputTableName
+ ' (ServerName, CheckDate, AnalysisVersion, CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, Op) SELECT '''
+ CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))
+ ''', GETDATE(), ' + CAST(@Version AS NVARCHAR(128))
+ ', CheckID, Priority, FindingsGroup, Finding, URL, Details, HowToStopIt, QueryPlan, QueryText, StartTime, LoginName, NTUserName, OriginalLoginName, ProgramName, HostName, DatabaseID, DatabaseName, OpenTransactionCount FROM #AnalysisResults ORDER BY Priority , FindingsGroup , Finding , Details';
EXEC(@StringToExecute);
END
ELSE IF (SUBSTRING(@OutputTableName, 2, 1) = '#')
BEGIN
RAISERROR('Due to the nature of Dymamic SQL, only global (i.e. double pound (##)) temp tables are supported for @OutputTableName', 16, 0)
END


DECLARE @separator AS VARCHAR(1);
IF @OutputType = 'RSV'
SET @separator = CHAR(31);
ELSE
SET @separator = ',';

IF @OutputType = 'COUNT'
BEGIN
SELECT  COUNT(*) AS Warnings
FROM    #AnalysisResults
END
ELSE
IF @OutputType IN ( 'CSV', 'RSV' )
BEGIN

SELECT  Result = CAST([Priority] AS NVARCHAR(100))
+ @separator + CAST(CheckID AS NVARCHAR(100))
+ @separator + COALESCE([FindingsGroup],
'(N/A)') + @separator
+ COALESCE([Finding], '(N/A)') + @separator
+ COALESCE(DatabaseName, '(N/A)') + @separator
+ COALESCE([URL], '(N/A)') + @separator
+ COALESCE([Details], '(N/A)')
FROM    #AnalysisResults
ORDER BY Priority ,
FindingsGroup ,
Finding ,
Details;
END
ELSE IF @ExpertMode = 0 AND @OutputXMLasNVARCHAR = 0
BEGIN
SELECT  [Priority] ,
[FindingsGroup] ,
[Finding] ,
--[URL] ,
CAST([Details] AS [XML]) AS Details,
[HowToStopIt],
[QueryText],
[QueryPlan]
FROM    #AnalysisResults
ORDER BY Priority ,
FindingsGroup ,
Finding ,
ID;
END
ELSE IF @ExpertMode = 0 AND @OutputXMLasNVARCHAR = 1
BEGIN
SELECT  [Priority] ,
[FindingsGroup] ,
[Finding] ,
--[URL] ,
CAST([Details] AS NVARCHAR(MAX)) AS Details,
CAST([HowToStopIt] AS NVARCHAR(MAX)) AS HowToStopIt,
CAST([QueryText] AS NVARCHAR(MAX)) AS QueryText,
CAST([QueryPlan] AS NVARCHAR(MAX)) AS QueryPlan
FROM    #AnalysisResults
ORDER BY Priority ,
FindingsGroup ,
Finding ,
ID;
END
ELSE IF @ExpertMode = 1
BEGIN
SELECT  [Priority] ,
[FindingsGroup] ,
[Finding] ,
--[URL] ,
CAST([Details] AS [XML]) AS Details,
[HowToStopIt] ,
[CheckID] ,
[StartTime],
[LoginName],
[NTUserName],
[OriginalLoginName],
[ProgramName],
[HostName],
[DatabaseID],
[DatabaseName],
[OpenTransactionCount],
[QueryPlan],
[QueryText]
FROM    #AnalysisResults
ORDER BY Priority ,
FindingsGroup ,
Finding ,
ID;

-------------------------
--What happened: #WaitStats
-------------------------
;with max_batch as (
select max(SampleTime) as SampleTime
from #WaitStats
)
SELECT
'WAIT STATS' as Pattern,
b.SampleTime as [Sample Ended],
datediff(ss,wd1.SampleTime, wd2.SampleTime) as [Seconds Sample],
wd1.wait_type,
c.[Wait Time (Seconds)],
c.[Signal Wait Time (Seconds)],
CASE WHEN c.[Wait Time (Seconds)] > 0
THEN CAST(100.*(c.[Signal Wait Time (Seconds)]/c.[Wait Time (Seconds)]) as NUMERIC(4,1))
ELSE 0 END AS [Percent Signal Waits],
(wd2.waiting_tasks_count - wd1.waiting_tasks_count) AS [Number of Waits],
CASE WHEN (wd2.waiting_tasks_count - wd1.waiting_tasks_count) > 0
THEN
cast((wd2.wait_time_ms-wd1.wait_time_ms)/
(1.0*(wd2.waiting_tasks_count - wd1.waiting_tasks_count)) as numeric(10,1))
ELSE 0 END AS [Avg ms Per Wait]
FROM  max_batch b
JOIN #WaitStats wd2 on
wd2.SampleTime =b.SampleTime
JOIN #WaitStats wd1 ON
wd1.wait_type=wd2.wait_type AND
wd2.SampleTime > wd1.SampleTime
CROSS APPLY (SELECT
cast((wd2.wait_time_ms-wd1.wait_time_ms)/1000. as numeric(10,1)) as [Wait Time (Seconds)],
cast((wd2.signal_wait_time_ms - wd1.signal_wait_time_ms)/1000. as numeric(10,1)) as [Signal Wait Time (Seconds)]) AS c
WHERE (wd2.waiting_tasks_count - wd1.waiting_tasks_count) > 0
and wd2.wait_time_ms-wd1.wait_time_ms > 0
ORDER BY [Wait Time (Seconds)] DESC;


-------------------------
--What happened: #FileStats
-------------------------
WITH readstats as (
SELECT 'PHYSICAL READS' as Pattern,
ROW_NUMBER() over (order by wd2.avg_stall_read_ms desc) as StallRank,
wd2.SampleTime as [Sample Time],
datediff(ss,wd1.SampleTime, wd2.SampleTime) as [Sample (seconds)],
wd1.DatabaseName ,
wd1.FileLogicalName AS [File Name],
UPPER(SUBSTRING(wd1.PhysicalName, 1, 2)) AS [Drive] ,
wd1.SizeOnDiskMB ,
( wd2.num_of_reads - wd1.num_of_reads ) AS [# Reads/Writes],
CASE WHEN wd2.num_of_reads - wd1.num_of_reads > 0
 THEN CAST(( wd2.bytes_read - wd1.bytes_read)/1024./1024. AS NUMERIC(21,1))
 ELSE 0
END AS [MB Read/Written],
wd2.avg_stall_read_ms AS [Avg Stall (ms)],
wd1.PhysicalName AS [file physical name]
FROM #FileStats wd2
JOIN #FileStats wd1 ON wd2.SampleTime > wd1.SampleTime
 AND wd1.DatabaseID = wd2.DatabaseID
 AND wd1.FileID = wd2.FileID
),
writestats as (
SELECT
'PHYSICAL WRITES' as Pattern,
ROW_NUMBER() over (order by wd2.avg_stall_write_ms desc) as StallRank,
wd2.SampleTime as [Sample Time],
datediff(ss,wd1.SampleTime, wd2.SampleTime) as [Sample (seconds)],
wd1.DatabaseName ,
wd1.FileLogicalName AS [File Name],
UPPER(SUBSTRING(wd1.PhysicalName, 1, 2)) AS [Drive] ,
wd1.SizeOnDiskMB ,
( wd2.num_of_writes - wd1.num_of_writes ) AS [# Reads/Writes],
CASE WHEN wd2.num_of_writes - wd1.num_of_writes > 0
 THEN CAST(( wd2.bytes_written - wd1.bytes_written)/1024./1024. AS NUMERIC(21,1))
 ELSE 0
END AS [MB Read/Written],
wd2.avg_stall_write_ms AS [Avg Stall (ms)],
wd1.PhysicalName AS [file physical name]
FROM #FileStats wd2
JOIN #FileStats wd1 ON wd2.SampleTime > wd1.SampleTime
 AND wd1.DatabaseID = wd2.DatabaseID
 AND wd1.FileID = wd2.FileID
)
SELECT
Pattern, [Sample Time], [Sample (seconds)], [File Name], [Drive],  [# Reads/Writes],[MB Read/Written],[Avg Stall (ms)], [file physical name]
from readstats
where StallRank <=5 and [MB Read/Written] > 0
union all
SELECT Pattern, [Sample Time], [Sample (seconds)], [File Name], [Drive],  [# Reads/Writes],[MB Read/Written],[Avg Stall (ms)], [file physical name]
from writestats
where StallRank <=5 and [MB Read/Written] > 0;


-------------------------
--What happened: #PerfmonStats
-------------------------

SELECT 'PERFMON' AS Pattern, pLast.[object_name], pLast.counter_name, pLast.instance_name,
pFirst.SampleTime AS FirstSampleTime, pFirst.cntr_value AS FirstSampleValue,
pLast.SampleTime AS LastSampleTime, pLast.cntr_value AS LastSampleValue,
pLast.cntr_value - pFirst.cntr_value AS ValueDelta,
((1.0 * pLast.cntr_value - pFirst.cntr_value) / DATEDIFF(ss, pFirst.SampleTime, pLast.SampleTime)) AS ValuePerSecond
FROM #PerfmonStats pLast
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))
AND pLast.ID > pFirst.ID
ORDER BY Pattern, pLast.[object_name], pLast.counter_name, pLast.instance_name


-------------------------
--What happened: #FileStats
-------------------------
SELECT qsNow.*, qsFirst.*
FROM #QueryStats qsNow
 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
WHERE qsNow.Pass = 2
END

DROP TABLE #AnalysisResults;


END /* IF @Question IS NULL */
ELSE IF @Question IS NOT NULL

/* We're playing Magic SQL 8 Ball, so give them an answer. */
BEGIN
IF OBJECT_ID('tempdb..#Answers') IS NOT NULL
DROP TABLE #Answers;
CREATE TABLE #Answers(Answer VARCHAR(200) NOT NULL);
INSERT INTO #Answers VALUES ('It sounds like a SAN problem.');
SELECT TOP 1 Answer FROM #Answers ORDER BY NEWID();
END

END /* ELSE IF @OutputType = 'SCHEMA' */


SET NOCOUNT OFF;

New Features in SQL server 2016

This summary is not available. Please click here to view the post.