Technical Article

SQL Server Heath Check Script

,

We can get the mail to run SQL server Health check like services, databases, Always On, replication, CDC job status.

First, we need to create CMS (Centralized Managment Server ) and run the below script to get the result.

1. Health check after Windows or SQL Patch
2. Daily Heath check
The script below queries for SQL server patch details and SQL services start details
 
SELECT @@SERVERNAME as ServerName,@@ServiceName as [InstanceName],
case
when convert(varchar(100), SERVERPROPERTY(N'ProductVersion')) like '16.%' then 'SQL Server 2022'
when convert(varchar(100), SERVERPROPERTY(N'ProductVersion')) like '15.%' then 'SQL Server 2019'
when convert(varchar(100), SERVERPROPERTY(N'ProductVersion')) like '14.%' then 'SQL Server 2017'
when convert(varchar(100), SERVERPROPERTY(N'ProductVersion')) like '13.%' then 'SQL Server 2016'
when convert(varchar(100), SERVERPROPERTY(N'ProductVersion')) like '12.%' then 'SQL Server 2014'
when convert(varchar(100), SERVERPROPERTY(N'ProductVersion')) like '11.%' then 'SQL Server 2012'
when convert(varchar(100),SERVERPROPERTY(N'ProductVersion')) like '10.5%' then 'SQL Server 2008R2'
when convert(varchar(100),SERVERPROPERTY(N'ProductVersion')) like '10.0%' then 'SQL Server 2008'
when convert(varchar(100),SERVERPROPERTY(N'ProductVersion')) like '10.0%' then 'SQL Server 2008'
when convert(varchar(100),SERVERPROPERTY(N'ProductVersion')) like '9.0%' then 'SQL Server 2005'
else 'Not Found'
end as VersionName,
SERVERPROPERTY(N'ProductVersion') AS [Number],
SERVERPROPERTY('ProductLevel') AS SP,
CAST(SERVERPROPERTY(N'Edition') AS sysname) AS [Edition]

sqlserver_start_time FROM sys.dm_os_sys_info

***********1. Health check when apply Windows patch or SQL patch
--DB Status--


select
a.name,
a.state_desc,
case
When a.state = 0 then 'ONLINE'
when a.state = 1 then 'RESTORING'
when a.state = 2 then 'RECOVERING'
when a.state = 3 then 'RECOVERY_PENDING'
when a.state = 4 then 'SUSPECT'
when a.state = 5 then 'EMERGENCY'
when a.state = 6 then 'OFFLINE'
when a.state = 7 then 'COPYING - SQL AZURE'
when a.state = 10 then 'OFLINE_SECONDARY - SQL AZURE'
end
from sys.databases a where a.state<>0




--SQL Services Script--
DECLARE @ServiceStatus TABLE
(ServerName nvarchar(50)
,ServiceName nvarchar(50)
,StatusOfService nvarchar(20)
,StatusAsOn datetime)


INSERT INTO @ServiceStatus (StatusOfService)
EXEC master..xp_servicecontrol 'QueryState', 'MSSQL'
UPDATE @ServiceStatus
  SET ServerName=@@SERVERNAME
  ,ServiceName='MSSQL Server'
  ,StatusAsOn=GETDATE()
WHERE ServerName IS NULL


INSERT INTO @ServiceStatus (StatusOfService)
EXEC master..xp_servicecontrol 'QueryState', 'SQLAgent'
UPDATE @ServiceStatus
  SET ServerName=@@SERVERNAME
  ,ServiceName='SQL Server Agent'
  ,StatusAsOn=GETDATE()
WHERE ServerName IS NULL


INSERT INTO @ServiceStatus (StatusOfService)
EXEC master..xp_servicecontrol 'QueryState', 'SQLBrowser'
UPDATE @ServiceStatus
  SET ServerName=@@SERVERNAME
  ,ServiceName='SQL Server Browser'
  ,StatusAsOn=GETDATE()
WHERE ServerName IS NULL


SELECT * FROM @ServiceStatus where StatusOfService='Stopped.' and ServiceName!='SQL Server Browser'


--CDC Check
select name from msdb.dbo.sysjobs_view where name like '%cdc.%capture%'




--Always-ON
select database_id, synchronization_state_desc,synchronization_state,synchronization_health,synchronization_health_desc from sys.dm_hadr_database_replica_states


--Always-ON ----
SELECT RCS.replica_server_name,ARS.role_desc
  FROM master.sys.availability_groups_cluster AS AGC  INNER JOIN
             master.sys.dm_hadr_availability_replica_cluster_states AS RCS ON RCS.group_id = AGC.group_id INNER JOIN
             master.sys.dm_hadr_availability_replica_states AS ARS ON ARS.replica_id = RCS.replica_id    INNER JOIN
             master.sys.availability_group_listeners AS AGL ON AGL.group_id = ARS.group_id


--Replication:
SELECT  activity.start_execution_date, job.name, category.name AS Job_Category
,job.originating_server,ROW_NUMBER() OVER (ORDER BY job.name) AS RowID
FROM.msdb.dbo.sysjobs_view AS job INNER JOIN
             .msdb.dbo.sysjobactivity AS activity ON job.job_id = activity.job_id INNER JOIN
             .msdb.dbo.syscategories AS category ON job.category_id = category.category_id
WHERE     (activity.start_execution_date >= GETDATE()-02
  AND (activity.stop_execution_date IS NULL)
   AND job.category_id IN (10, 13))


***********************2. Daily Health Check*****************

----------------1. Database Status----------------

SELECT name,
DATABASEPROPERTYEX(name, 'Recovery'),
DATABASEPROPERTYEX(name, 'Status')
FROM master.dbo.sysdatabases
ORDER BY 1

------------------2. Services Info----------------

exec master.dbo.xp_servicecontrol 'QUERYSTATE', 'MSSQLServer'
exec master.dbo.xp_servicecontrol 'QUERYSTATE', 'SQLServerAgent'

------------------3. space info----------------

xp_fixeddrives

------------------4. Log file size----------------

dbcc sqlperf ('Logspace') - some database needs permission -DB access issue.

------------------5. disk space Data & log ----------------

create table #logsize
(Dbname varchar(200),dbstatus varchar(50),Recovery_Model varchar(40) default ('NA'), Log_File_Size_MB decimal(20,2)default (0),
log_Space_Used_MB decimal(20,2)default (0),log_Free_Space_MB decimal(20,2)default (0))
go

insert into #logsize(Dbname,dbstatus,recovery_model,Log_File_Size_MB,log_Space_Used_MB,log_Free_Space_MB)
exec sp_msforeachdb
'use [?];
select DB_NAME() AS DbName,
CONVERT(varchar(20),DatabasePropertyEx(''?'',''Status'')) ,
CONVERT(varchar(20),DatabasePropertyEx(''?'',''Recovery'')),
sum(size)/128.0 AS Log_File_Size_MB,
sum(CAST(FILEPROPERTY(name, ''SpaceUsed'') AS INT))/128.0 as log_Space_Used_MB,
SUM( size)/128.0 - sum(CAST(FILEPROPERTY(name,''SpaceUsed'') AS INT))/128.0 AS log_Free_Space_MB
from sysfiles where groupid=0 group by groupid
'
go

create table #dbsize
(Dbname varchar(200), file_Size_MB decimal(20,2)default (0),Space_Used_MB decimal(20,2)default (0),
Free_Space_MB decimal(20,2) default (0))
go

insert into #dbsize(Dbname,file_Size_MB,Space_Used_MB,Free_Space_MB)
exec sp_msforeachdb
'use [?];
select DB_NAME() AS DbName,

sum(size)/128.0 AS File_Size_MB,
sum(CAST(FILEPROPERTY(name, ''SpaceUsed'') AS INT))/128.0 as Space_Used_MB,
SUM( size)/128.0 - sum(CAST(FILEPROPERTY(name,''SpaceUsed'') AS INT))/128.0 AS Free_Space_MB
from sysfiles where groupid<>0 group by groupid '

go

select
d.Dbname,l.dbstatus,l.recovery_model,
(file_size_mb + log_file_size_mb) as DBsize,
d.file_Size_MB,d.Space_Used_MB,d.Free_Space_MB,
l.Log_File_Size_MB,log_Space_Used_MB,l.log_Free_Space_MB
from #dbsize d join #logsize l
on d.Dbname=l.Dbname




------------------6. Backup Job History----------------

SET NOCOUNT ON
GO
SET quoted_identifier OFF
DECLARE @dbname AS VARCHAR(80)
DECLARE @msgdb AS VARCHAR(100)
DECLARE @dbbkpname AS VARCHAR(80)
DECLARE @dypart1 AS VARCHAR(2)
DECLARE @dypart2 AS VARCHAR(3)
DECLARE @dypart3 AS VARCHAR(4)
DECLARE @currentdate AS VARCHAR(10)
DECLARE @server_name AS VARCHAR(30)
SELECT @server_name = @@servername
SELECT @dypart1 = DATEPART(dd,GETDATE())
SELECT @dypart2 = DATENAME(mm,GETDATE())
SELECT @dypart3 = DATEPART(yy,GETDATE())
SELECT @currentdate= @dypart1 + @dypart2 + @dypart3
PRINT "#####################################################################"
PRINT "# SERVERNAME : "+ @server_name + " DATE : "+ @currentdate +"#"
PRINT "#####################################################################"
PRINT "DatabaseName Full Diff TranLog"
PRINT "##########################################################################################################################################"
SELECT SUBSTRING(s.name,1,50) AS 'DATABASE Name',
b.backup_start_date AS 'Full DB Backup Status',
c.backup_start_date AS 'Differential DB Backup Status',
d.backup_start_date AS 'Transaction Log Backup Status'
FROM MASTER..sysdatabases s
LEFT OUTER JOIN msdb..backupset b
ON s.name = b.database_name
AND b.backup_start_date =
(SELECT MAX(backup_start_date)AS 'Full DB Backup Status'
FROM msdb..backupset
WHERE database_name = b.database_name
AND TYPE = 'D') -- full database backups only, not log backups
LEFT OUTER JOIN msdb..backupset c
ON s.name = c.database_name
AND c.backup_start_date =
(SELECT MAX(backup_start_date)'Differential DB Backup Status'
FROM msdb..backupset
WHERE database_name = c.database_name
AND TYPE = 'I')
LEFT OUTER JOIN msdb..backupset d
ON s.name = d.database_name
AND d.backup_start_date =
(SELECT MAX(backup_start_date)'Transaction Log Backup Status'
FROM msdb..backupset
WHERE database_name = d.database_name
AND TYPE = 'L')
WHERE s.name <>'tempdb'
ORDER BY s.name
-----

use msdb
go

-- D = Full, I = Differential and L = Log.
-- There are other types of backups too but those are the primary ones.
SELECT backupset.database_name,
MAX(CASE WHEN backupset.type = 'D' THEN backupset.backup_finish_date ELSE NULL END) AS LastFullBackup,
MAX(CASE WHEN backupset.type = 'I' THEN backupset.backup_finish_date ELSE NULL END) AS LastDifferential,
MAX(CASE WHEN backupset.type = 'L' THEN backupset.backup_finish_date ELSE NULL END) AS LastLog
FROM backupset
GROUP BY backupset.database_name
ORDER BY backupset.database_name DESC

Rate

You rated this post out of 5. Change rating

Share

Share

Rate

You rated this post out of 5. Change rating