The following script will help to do a quick health check of SQL estate that you manage. To check all SQL server health check, you need to create Registered or Centralized server.
I usually automated everything using my AutoMon script package that will trigger an email from CMS server. But, some small clients and where I do not have long term scope, I use Registered Server and will run various script than the health check like – DB list, Login list & agent job list etc.
-- 1) Disk Free Space Check
XP_FIXEDDRIVES
-- 2) DB Online Status (Including SQL 2000)
SELECT NAME,DATABASEPROPERTYEX (NAME,'STATUS') AS STATUS, GETDATE() as [Today_Date]
FROM MASTER.DBO.SYSDATABASES WHERE DATABASEPROPERTYEX (NAME,'STATUS') NOT IN ('ONLINE')
go
WITH DB_STATUS AS
(
SELECT NAME,DB_STATE = CASE
WHEN STATUS = 67584 THEN 'Restricted User'
WHEN STATUS = 69632 THEN 'Single User'
WHEN STATUS = 98560 THEN 'Emergency Mode'
WHEN STATUS = 128 THEN 'Recovering'
ELSE 'Unchecked' END, GETDATE() as [Today_Date]
FROM MASTER.DBO.SYSDATABASES
)
SELECT * FROM DB_STATUS WHERE DB_STATE NOT IN ('Unchecked')
-- 3) Failled Job check
DECLARE @Date CHAR(8);
SET @Date= CONVERT(CHAR(8), DATEADD(HH,-24,GETDATE()),112)
SELECT
@@SERVERNAME AS [Server Name],
SUBSTRING(T2.name,1,140) AS [SQL Job Name],
T1.step_name AS [Step Name],
--msdb.dbo.agent_datetime(run_date, run_time) as 'RunDateTime',
COUNT(*) AS TotalFailures,
CAST(MIN(CONVERT(DATETIME,CAST(run_date AS CHAR(8)),101)) AS CHAR(11)) AS [MinFailure Date],
CAST(MAX(CONVERT(DATETIME,CAST(run_date AS CHAR(8)),101)) AS CHAR(11)) AS [MaxFailure Date],
GETDATE() as [Today_Date],
--MAX(msdb.dbo.agent_datetime(T1.run_date, T1.run_time)) AS 'RunDateTime',
MIN(T1.run_duration) StepDuration,
CASE MIN(T1.run_status)
WHEN 0 THEN 'Failed'
WHEN 1 THEN 'Succeeded'
WHEN 2 THEN 'Retry'
WHEN 3 THEN 'Cancelled'
WHEN 4 THEN 'In Progress'
END AS ExecutionStatus,
MAX(T1.message) AS [Error Message]
FROM
msdb..sysjobhistory T1 INNER JOIN msdb..sysjobs T2 ON T1.job_id = T2.job_id
WHERE
T1.run_status NOT IN (1,2,4)
AND T1.step_id != 0
AND run_date >= @Date
--AND step_name NOT LIKE '%%'
GROUP BY
T1.step_name,
T2.name
-- 4) Always ON check
SELECT name, role_desc, operational_state_desc, recovery_health_desc,
synchronization_health_desc, Getdate() as [Today_Date]
FROM SYS.DM_HADR_AVAILABILITY_REPLICA_CLUSTER_STATES A
JOIN SYS.DM_HADR_AVAILABILITY_REPLICA_STATES B ON A.group_id=B.group_id
JOIN SYS.AVAILABILITY_GROUPS_CLUSTER C ON B.group_id =C.group_id
WHERE B.synchronization_health_desc NOT IN ('HEALTHY')
-- Logshipping & DB Mirroring
-- 5) Long running process
-- Long running process based on last login time
select db_name(dbid) as DBName , Cmd, Status as [Run_Status],datediff(minute,login_time,getdate()) as [Runtime_minute]
,spid,blocked,lastwaittype,waittime,hostname,program_name,loginame,login_time from sysprocesses
where spid > 51 and status not in ('background','sleeping')
and datediff(minute,login_time,getdate()) >5 -- more than 5 minutes
--and cmd not in ('waitfor','awaiting command')
--and not in dbid (1,2,3,4)
group by dbid,Cmd, Status ,login_time,spid,blocked,lastwaittype,waittime,hostname,program_name,loginame,login_time