May 3, 2020

SQL Server AlwaysON Health Check...



--Below SQL Script can we use for check SQL Server AG HEALTH 





USE [TempDB]
SET NOCOUNT ON
GO

SELECT CurrentTime_UTC = SYSUTCDATETIME()

DECLARE @XELTarget VARCHAR(MAX);
DECLARE @XELPath VARCHAR(MAX);
DECLARE @XELFile VARCHAR(max);

IF EXISTS(SELECT name FROM sys.dm_xe_sessions WHERE name = 'AlwaysOn_Health') BEGIN
SELECT @XELTarget = cast(xet.target_data AS XML).value('(EventFileTarget/File/@name)[1]', 'VARCHAR(MAX)')
FROM sys.dm_xe_sessions xes
INNER JOIN sys.dm_xe_session_targets xet
ON xes.address = xet.event_session_address
WHERE xet.target_name = 'event_file' and xes.name = 'AlwaysOn_Health'

SELECT @XELPath = REVERSE(SUBSTRING(REVERSE(@XELTarget),
CHARINDEX('\', reverse(@XELTarget)),
LEN(@XELTarget)+1- CHARINDEX('\', REVERSE(@XELTarget))))

SELECT @XELFile = @XELPath + 'AlwaysOn_health*.xel'
IF @XELFile IS NULL BEGIN
PRINT 'Unable to find XEVent target files for AlwaysOn_Health XEvent session'
PRINT 'Expected AOHealth XEvent files in this location:'
PRINT @XELPath
RETURN
END
END ELSE BEGIN
PRINT 'No AlwaysOn Health XEvent session found'
RETURN
END


--create table
DECLARE @AOHealth_XELData TABLE --CREATE TABLE @AOHealth_XELData
    (ID INT IDENTITY PRIMARY KEY CLUSTERED,
    object_name varchar(max),
    EventData XML,
    file_name varchar(max),
    file_offset bigint);

--read from the files into the table
IF @XELFile IS NOT NULL BEGIN
INSERT INTO @AOHealth_XELData
SELECT object_name, cast(event_data as XML) AS EventData,
 file_name, File_Offset
 FROM sys.fn_xe_file_target_read_file(
 @XELFile, NULL, null, null);
END

-- Create table for "error_reported" events
DECLARE @error_reported TABLE --CREATE TABLE @error_reported
(Xevent varchar(15),
TimeStamp_UTC varchar(75),  --because sometimes it's a long integer because of an internal bug
error_number INT,
severity INT,
state INT,
user_defined varchar(5),
category_desc varchar(25),
category varchar(5),
destination varchar(20),
destination_desc varchar(20),
is_intercepted varchar(5),
message varchar(max))

INSERT INTO @error_reported
SELECT  CAST(object_name as varchar(15)) AS Xevent,
CASE WHEN
ISDATE(EventData.value('(event/@timestamp)[1]', 'varchar(25)') ) =0
THEN NULL
ELSE CAST(EventData.value('(event/@timestamp)[1]', 'datetimeoffset(2)') as DATETIMEOFFSET(2))
END
AS TimeStamp_UTC,
    EventData.value('(event/data[@name="error_number"]/value)[1]', 'int') AS error_number,
    EventData.value('(event/data[@name="severity"]/value)[1]', 'int') AS severity,
    EventData.value('(event/data[@name="state"]/value)[1]', 'int') AS state,
    EventData.value('(event/data[@name="user_defined"]/value)[1]', 'varchar(5)') AS user_defined,
    EventData.value('(event/data[@name="category"]/text)[1]', 'varchar(25)') AS category_desc,
    EventData.value('(event/data[@name="category"]/value)[1]', 'varchar(5)') AS category,
    EventData.value('(event/data[@name="destination"]/value)[1]', 'varchar(20)') AS destination,
    EventData.value('(event/data[@name="destination"]/text)[1]', 'varchar(20)') AS destination_desc,
    EventData.value('(event/data[@name="is_intercepted"]/value)[1]', 'varchar(5)') AS is_intercepted,
    EventData.value('(event/data[@name="message"]/value)[1]', 'varchar(max)') AS message
    FROM @AOHealth_XELData
    WHERE EventData.value('(event/@name)[1]', 'varchar(max)') = 'error_reported';

IF EXISTS(SELECT * FROM @error_reported) BEGIN
PRINT 'Error event stats'
PRINT '=================';
--display results from "error_reported" event data
WITH ErrorCTE (ErrorNum, ErrorCount, FirstDate_UTC, LastDate_UTC) AS (
SELECT error_number, Count(error_number), min(TimeStamp_UTC), max(TimeStamp_UTC) As ErrorCount
FROM @error_reported
GROUP BY error_number)
SELECT ErrorNum,
ErrorCount,--CAST(ErrorCount as CHAR(10)) ErrorCount,
CONVERT(datetimeoffset(2), FirstDate_UTC,121)   as FirstDate_UTC,
CONVERT(datetimeoffset(2), LastDate_UTC, 121)   as LastDate_UTC,
CAST(CASE ErrorNum
WHEN 35202 THEN 'A connection for availability group ... has been successfully established...'
WHEN 1480 THEN 'The %S_MSG database "%.*ls" is changing roles ... because the AG failed over ...'
WHEN 35206 THEN 'A connection timeout has occurred on a previously established connection ...'
WHEN 35201 THEN 'A connection timeout has occurred while attempting to establish a connection ...'
WHEN 41050 THEN 'Waiting for local WSFC service to start.'
WHEN 41051 THEN 'Local WSFC service started.'
WHEN 41052 THEN 'Waiting for local WSFC node to start.'
WHEN 41053 THEN 'Local WSFC node started.'
WHEN 41054 THEN 'Waiting for local WSFC node to come online.'
WHEN 41055 THEN 'Local WSFC node is online.'
WHEN 41048 THEN 'Local WSFC service has become unavailable.'
WHEN 41049 THEN 'Local WSFC node is no longer online.'
ELSE m.text END AS VARCHAR(81)) [Abbreviated Message]
FROM
ErrorCTE ec LEFT JOIN sys.messages m on ec.ErrorNum = m.message_id
and m.language_id = 1033
order by LastDate_UTC DESC, ErrorCount DESC
END

IF EXISTS(SELECT object_name FROM @AOHealth_XELData WHERE object_name = 'alwayson_ddl_executed')
BEGIN
PRINT 'Non-failover DDL Events';
PRINT '=======================';
WITH AODDL (object_name, TimeStamp_UTC, ddl_action, ddl_action_desc, ddl_phase, ddl_phase_desc,
availability_group_name, availability_group_id, [statement])
AS
(
SELECT  object_name, CASE WHEN
ISDATE(EventData.value('(event/@timestamp)[1]', 'varchar(25)') ) =0
THEN NULL
ELSE CAST(EventData.value('(event/@timestamp)[1]', 'datetimeoffset(2)') as DATETIMEOFFSET(2))
END
AS TimeStamp_UTC,
EventData.value('(event/data[@name="ddl_action"]/value)[1]', 'int') AS ddl_action,
EventData.value('(event/data[@name="ddl_action"]/text)[1]', 'varchar(15)') AS ddl_action_desc,
EventData.value('(event/data[@name="ddl_phase"]/value)[1]', 'int') AS ddl_phase,
EventData.value('(event/data[@name="ddl_phase"]/text)[1]', 'varchar(10)') AS ddl_phase_desc,
EventData.value('(event/data[@name="availability_group_name"]/value)[1]', 'varchar(25)') AS availability_group_name,
EventData.value('(event/data[@name="availability_group_id"]/value)[1]', 'varchar(36)') AS availability_group_id,
EventData.value('(event/data[@name="statement"]/value)[1]', 'varchar(max)') AS [statement]
FROM @AOHealth_XELData
WHERE object_name = 'alwayson_ddl_executed'
AND EventData.value('(event/data[@name="statement"]/value)[1]', 'varchar(max)') NOT LIKE '%FAILOVER%'
OR (EventData.value('(event/data[@name="statement"]/value)[1]', 'varchar(max)') LIKE '%FAILOVER%' AND
EventData.value('(event/data[@name="statement"]/value)[1]', 'varchar(max)') LIKE '%CREATE%')
)
SELECT cast(object_name as varchar(22)) AS XEvent, TimeStamp_UTC, ddl_action, ddl_action_desc, ddl_phase,
ddl_phase_desc, availability_group_name, availability_group_id,
CASE WHEN LEN([statement]) > 220
THEN CAST([statement] as varchar(1155)) + char(10)
ELSE CAST(Replace([statement], char(10), '') as varchar(220))
END as [statement]
FROM AODDL
ORDER BY TimeStamp_UTC desc;


PRINT 'Failover DDL Events';
PRINT '===================';
-- Display results "alwayson_ddl_executed" events
WITH AODDL (object_name, TimeStamp_UTC, ddl_action, ddl_action_desc, ddl_phase, ddl_phase_desc,
availability_group_name, availability_group_id, [statement])
AS
(
SELECT  object_name, CASE WHEN
ISDATE(EventData.value('(event/@timestamp)[1]', 'varchar(25)') ) =0
THEN NULL
ELSE CAST(EventData.value('(event/@timestamp)[1]', 'datetimeoffset(2)') as DATETIMEOFFSET(2))
END
AS TimeStamp_UTC,
EventData.value('(event/data[@name="ddl_action"]/value)[1]', 'int') AS ddl_action,
EventData.value('(event/data[@name="ddl_action"]/text)[1]', 'varchar(15)') AS ddl_action_desc,
EventData.value('(event/data[@name="ddl_phase"]/value)[1]', 'int') AS ddl_phase,
EventData.value('(event/data[@name="ddl_phase"]/text)[1]', 'varchar(10)') AS ddl_phase_desc,
EventData.value('(event/data[@name="availability_group_name"]/value)[1]', 'varchar(25)') AS availability_group_name,
EventData.value('(event/data[@name="availability_group_id"]/value)[1]', 'varchar(36)') AS availability_group_id,
EventData.value('(event/data[@name="statement"]/value)[1]', 'varchar(max)') AS [statement]
FROM @AOHealth_XELData
WHERE object_name = 'alwayson_ddl_executed'
AND (EventData.value('(event/data[@name="statement"]/value)[1]', 'varchar(max)') LIKE '%FAILOVER%'
OR EventData.value('(event/data[@name="statement"]/value)[1]', 'varchar(max)') LIKE '%FORCE%')
AND EventData.value('(event/data[@name="statement"]/value)[1]', 'varchar(max)') NOT LIKE '%CREATE%'
)
SELECT cast(object_name as varchar(22)) AS XEvent, TimeStamp_UTC, ddl_action, ddl_action_desc, ddl_phase,
ddl_phase_desc, availability_group_name, availability_group_id,
CAST(Replace([statement], char(10), '') as varchar(80)) as [statement]
FROM AODDL
ORDER BY TimeStamp_UTC desc;
END

IF EXISTS(SELECT object_name FROM @AOHealth_XELData WHERE object_name = 'availability_replica_manager_state_change')
BEGIN
PRINT 'Availability Replica Manager state changes'
PRINT '==========================================';
-- display results for "availability_replica_manager_state_change" events
SELECT cast(object_name as varchar(42)) AS XEvent, CASE WHEN
ISDATE(EventData.value('(event/@timestamp)[1]', 'varchar(25)') ) =0
THEN NULL
ELSE CAST(EventData.value('(event/@timestamp)[1]', 'datetimeoffset(2)') as DATETIMEOFFSET(2))
END
AS TimeStamp_UTC,
EventData.value('(event/data[@name="current_state"]/value)[1]', 'int') AS current_state,
EventData.value('(event/data[@name="current_state"]/text)[1]', 'varchar(30)') AS current_state_desc
FROM @AOHealth_XELData
WHERE object_name = 'availability_replica_manager_state_change'
ORDER BY TimeStamp_UTC desc;
END


IF EXISTS(SELECT object_name FROM @AOHealth_XELData WHERE object_name = 'availability_replica_state')
BEGIN
PRINT 'Availability Replica state'
PRINT '==========================';
-- display results for "availability_replica_state" events
SELECT cast(object_name as varchar(34)) AS XEvent, CASE WHEN
ISDATE(EventData.value('(event/@timestamp)[1]', 'varchar(25)') ) =0
THEN NULL
ELSE CAST(EventData.value('(event/@timestamp)[1]', 'datetimeoffset(2)') as DATETIMEOFFSET(2))
END
AS TimeStamp_UTC,
EventData.value('(event/data[@name="current_state"]/value)[1]', 'int') AS current_state,
EventData.value('(event/data[@name="current_state"]/text)[1]', 'varchar(20)') AS current_state_desc,
EventData.value('(event/data[@name="availability_group_name"]/value)[1]', 'varchar(36)') AS availability_group_name,
EventData.value('(event/data[@name="availability_group_id"]/value)[1]', 'varchar(36)') AS availability_group_id,
EventData.value('(event/data[@name="availability_replica_id"]/value)[1]', 'varchar(36)') AS availability_replica_id
FROM @AOHealth_XELData
WHERE object_name = 'availability_replica_state'
ORDER BY TimeStamp_UTC desc;
END

IF EXISTS(SELECT object_name FROM @AOHealth_XELData WHERE object_name = 'availability_replica_state_change')
BEGIN
PRINT 'Availability Replica state changes'
PRINT '==================================';
-- display results for "availability_replica_state_change" events
SELECT cast(object_name as varchar(34)) AS XEvent, CASE WHEN
ISDATE(EventData.value('(event/@timestamp)[1]', 'varchar(25)') ) =0
THEN NULL
ELSE CAST(EventData.value('(event/@timestamp)[1]', 'datetimeoffset(2)') as DATETIMEOFFSET(2))
END
AS TimeStamp_UTC,
IsNULL(EventData.value('(event/data[@name="availability_replica_name"]/value)[1]', 'varchar(25)'), 'Data Unavailable') AS availability_replica_name,
EventData.value('(event/data[@name="availability_group_name"]/value)[1]', 'varchar(25)') AS availability_group_name,
EventData.value('(event/data[@name="previous_state"]/value)[1]', 'int') AS previous_state,
EventData.value('(event/data[@name="previous_state"]/text)[1]', 'varchar(30)') AS previous_state_desc,
EventData.value('(event/data[@name="current_state"]/value)[1]', 'int') AS current_state,
EventData.value('(event/data[@name="current_state"]/text)[1]', 'varchar(30)') AS current_state_desc,
EventData.value('(event/data[@name="availability_replica_id"]/value)[1]', 'varchar(36)') AS availability_replica_id,
EventData.value('(event/data[@name="availability_group_id"]/value)[1]', 'varchar(36)') AS availability_group_id
FROM @AOHealth_XELData
WHERE object_name = 'availability_replica_state_change'
ORDER BY TimeStamp_UTC DESC;
END

IF EXISTS(SELECT object_name FROM @AOHealth_XELData WHERE object_name = 'availability_group_lease_expired')
BEGIN
PRINT 'Lease Expiration Events'
PRINT '=======================';
-- Display results "lease expiration" events
SELECT  cast(object_name as varchar(33)) AS XEvent, CASE WHEN
ISDATE(EventData.value('(event/@timestamp)[1]', 'varchar(25)') ) =0
THEN NULL
ELSE CAST(EventData.value('(event/@timestamp)[1]', 'datetimeoffset(2)') as DATETIMEOFFSET(2))
END
AS TimeStamp_UTC,
EventData.value('(event/data[@name="availability_group_name"]/value)[1]', 'varchar(25)') AS AGName,
EventData.value('(event/data[@name="availability_group_id"]/value)[1]', 'varchar(36)') AS AG_ID
FROM @AOHealth_XELData
WHERE object_name = 'availability_group_lease_expired'
ORDER BY TimeStamp_UTC desc;
END

IF EXISTS(SELECT object_name FROM @AOHealth_XELData WHERE object_name = 'lock_redo_blocked')
BEGIN
PRINT 'BLOCKED REDO Events'
PRINT '===================';
-- Display results "lock_redo_blocked" events
SELECT cast(object_name as varchar(42)) AS XEvent, CASE WHEN
ISDATE(EventData.value('(event/@timestamp)[1]', 'varchar(25)') ) =0
THEN NULL
ELSE CAST(EventData.value('(event/@timestamp)[1]', 'datetimeoffset(2)') as DATETIMEOFFSET(2))
END
AS TimeStamp_UTC,
EventData.value('(event/data[@name="resource_type"]/value)[1]', 'int') AS ResourceType,
EventData.value('(event/data[@name="resource_type"]/text)[1]', 'varchar(25)') AS ResourceTypeDesc,
EventData.value('(event/data[@name="mode"]/value)[1]', 'int') AS Mode,
EventData.value('(event/data[@name="mode"]/text)[1]', 'varchar(25)') AS ModeDesc,
EventData.value('(event/data[@name="owner_type"]/value)[1]', 'int') AS OwnerType,
EventData.value('(event/data[@name="owner_type"]/text)[1]', 'varchar(25)') AS OwnerTypeDesc,
EventData.value('(event/data[@name="transaction_id"]/value)[1]', 'bigint') AS transaction_id,
EventData.value('(event/data[@name="database_id"]/value)[1]', 'int') AS database_id,
EventData.value('(event/data[@name="lockspace_workspace_id"]/value)[1]', 'varchar(22)') AS lockspace_workspace_id,
EventData.value('(event/data[@name="lockspace_sub_id"]/value)[1]', 'bigint') AS lockspace_sub_id,
EventData.value('(event/data[@name="lockspace_nest_id"]/value)[1]', 'bigint') AS lockspace_nest_id,
EventData.value('(event/data[@name="resource_0"]/value)[1]', 'bigint') AS resource_0,
EventData.value('(event/data[@name="resource_1"]/value)[1]', 'bigint') AS resource_1,
EventData.value('(event/data[@name="resource_2"]/value)[1]', 'bigint') AS resource_2,
EventData.value('(event/data[@name="object_id"]/value)[1]', 'bigint') AS [object_id],
EventData.value('(event/data[@name="associated_object_id"]/value)[1]', 'bigint') AS associated_object_id,
EventData.value('(event/data[@name="duration"]/value)[1]', 'int') AS duration,
EventData.value('(event/data[@name="resource_description"]/value)[1]', 'varchar(25)') AS resource_description
FROM @AOHealth_XELData
WHERE object_name = 'lock_redo_blocked'
ORDER BY TimeStamp_UTC desc;
END

IF EXISTS(SELECT object_name FROM @AOHealth_XELData WHERE object_name = 'hadr_db_partner_set_sync_state')
BEGIN
PRINT 'hadr_db_partner_set_sync_state Events'
PRINT '=====================================';
-- Display results "hadr_db_partner_set_sync_state" events
  SELECT cast(object_name as varchar(42)) AS XEvent, CASE WHEN
ISDATE(EventData.value('(event/@timestamp)[1]', 'varchar(25)') ) =0
THEN NULL
ELSE CAST(EventData.value('(event/@timestamp)[1]', 'datetimeoffset(2)') as DATETIMEOFFSET(2))
END
AS TimeStamp_UTC,
EventData.value('(event/data[@name="database_id"]/value)[1]', 'int') AS database_id,
EventData.value('(event/data[@name="commit_policy"]/value)[1]', 'int') AS commit_policy,
EventData.value('(event/data[@name="commit_policy"]/text)[1]', 'varchar(20)') AS commit_policy_desc,
EventData.value('(event/data[@name="commit_policy_target"]/value)[1]', 'int') AS commit_policy_target,
EventData.value('(event/data[@name="commit_policy_target"]/text)[1]', 'varchar(20)') AS commit_policy_target_desc,
EventData.value('(event/data[@name="sync_state"]/value)[1]', 'int') AS sync_state,
EventData.value('(event/data[@name="sync_state"]/text)[1]', 'varchar(20)') AS sync_state_desc,
EventData.value('(event/data[@name="sync_log_block"]/value)[1]', 'varchar(20)') AS sync_log_block,
EventData.value('(event/data[@name="group_id"]/value)[1]', 'varchar(36)') AS group_id,
EventData.value('(event/data[@name="replica_id"]/value)[1]', 'varchar(36)') AS replica_id,
EventData.value('(event/data[@name="ag_database_id"]/value)[1]', 'varchar(36)') AS ag_database_id
FROM @AOHealth_XELData
WHERE object_name = 'hadr_db_partner_set_sync_state'
ORDER BY TimeStamp_UTC desc;
END

IF EXISTS(SELECT object_name FROM @AOHealth_XELData WHERE object_name = 'availability_replica_automatic_failover_validation')
BEGIN
PRINT 'availability_replica_automatic_failover_validation'
PRINT '==================================================';
-- Display results "availability_replica_automatic_failover_validation" events
  SELECT cast(object_name as varchar(50)) AS XEvent, CASE WHEN
ISDATE(EventData.value('(event/@timestamp)[1]', 'varchar(25)') ) =0
THEN NULL
ELSE CAST(EventData.value('(event/@timestamp)[1]', 'datetimeoffset(2)') as DATETIMEOFFSET(2))
END
AS TimeStamp_UTC,
EventData.value('(event/data[@name="availability_replica_name"]/value)[1]', 'varchar(25)') AS availability_replica_name,
EventData.value('(event/data[@name="availability_group_name"]/value)[1]', 'varchar(25)') AS availability_group_name,
EventData.value('(event/data[@name="availability_replica_id"]/value)[1]', 'varchar(36)') AS availability_replica_id,
EventData.value('(event/data[@name="availability_group_id"]/value)[1]', 'varchar(36)') AS availability_group_id,
EventData.value('(event/data[@name="forced_quorum"]/value)[1]', 'varchar(5)') AS forced_quorum,
EventData.value('(event/data[@name="joined_and_synchronized"]/value)[1]', 'varchar(5)') AS joined_and_synchronized,
EventData.value('(event/data[@name="previous_primary_or_automatic_failover_target"]/value)[1]', 'varchar(5)') AS previous_primary_or_automatic_failover_target
FROM @AOHealth_XELData
WHERE object_name = 'availability_replica_automatic_failover_validation'
ORDER BY TimeStamp_UTC desc;
END

DECLARE @AOHealthSummary TABLE --CREATE TABLE @AOHealthSummary
(XEvent varchar(50), [COUNT] INT);
INSERT INTO @AOHealthSummary
SELECT CAST(xv.event_name AS VARCHAR(50)), 0
FROM sys.dm_xe_sessions xes
INNER JOIN sys.dm_xe_session_events xv ON xes.address = xv.event_session_address
WHERE xes.name like 'AlwaysOn_Health'
ORDER BY event_name;

With Summary (XEvent, [Count])
AS (SELECT CAST(object_name AS VARCHAR(50)) AS [XEvent], count(*) AS [Count]
FROM @AOHealth_XELData
GROUP BY object_name)
UPDATE @AOHealthSummary
SET [COUNT] = s.[COUNT]
FROM Summary s
INNER JOIN @AOHealthSummary ao ON s.XEvent = ao.XEvent;

IF EXISTS(SELECT * FROM @AOHealthSummary) BEGIN
PRINT 'Summary event counts for AO Health XEvents'
PRINT '==========================================';
-- Display event counts for AO Health XEvent data
SELECT * FROM @AOHealthSummary
ORDER BY [count] DESC, XEvent
END

GO



No comments:

Post a Comment

If you have any doubt or question, please contact us.