From 99d7f5d8f34f6b0e77a7f6b371f9e4414dd9c1a1 Mon Sep 17 00:00:00 2001 From: Erik Darling <2136037+erikdarlingdata@users.noreply.github.com> Date: Fri, 27 Feb 2026 06:59:16 -0500 Subject: [PATCH] Skip non-readable AG secondary databases in cross-database collectors (#325) Collectors that iterate databases and USE/query into them now exclude AG secondary replicas configured with READ_ONLY connections, which reject non-read-intent sessions with "not accessible for queries" errors. Filter uses sys.availability_replicas.secondary_role_allow_connections_desc to identify secondaries that won't accept our connection type. Databases on primaries, non-AG databases, and secondaries with ALL connections continue to be collected normally. Changed locations: - install/39_collect_database_configuration.sql (scoped config cursor) - install/09_collect_query_store.sql (QS discovery cursor) - Lite/RemoteCollectorService.ServerConfig.cs (scoped config db list) - Lite/RemoteCollectorService.QueryStore.cs (QS discovery cursor) Clean install verified on sql2016 with zero errors. Co-Authored-By: Claude Opus 4.6 --- .../RemoteCollectorService.QueryStore.cs | 17 +++++++++++++++++ .../RemoteCollectorService.ServerConfig.cs | 17 +++++++++++++++++ install/09_collect_query_store.sql | 17 +++++++++++++++++ install/39_collect_database_configuration.sql | 17 +++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/Lite/Services/RemoteCollectorService.QueryStore.cs b/Lite/Services/RemoteCollectorService.QueryStore.cs index 737dd7f..53f8162 100644 --- a/Lite/Services/RemoteCollectorService.QueryStore.cs +++ b/Lite/Services/RemoteCollectorService.QueryStore.cs @@ -48,6 +48,23 @@ WHERE d.database_id > 4 AND d.database_id < 32761 AND d.state_desc = N'ONLINE' AND d.name <> N'PerformanceMonitor' + AND d.database_id NOT IN + ( + SELECT + d2.database_id + FROM sys.databases AS d2 + JOIN sys.availability_replicas AS r + ON d2.replica_id = r.replica_id + WHERE NOT EXISTS + ( + SELECT + 1/0 + FROM sys.dm_hadr_availability_group_states AS s + WHERE s.primary_replica = r.replica_server_name + ) + AND r.secondary_role_allow_connections_desc = N'READ_ONLY' + AND r.replica_server_name = @@SERVERNAME + ) OPTION(RECOMPILE); OPEN db_check; diff --git a/Lite/Services/RemoteCollectorService.ServerConfig.cs b/Lite/Services/RemoteCollectorService.ServerConfig.cs index 9adad48..b0f325f 100644 --- a/Lite/Services/RemoteCollectorService.ServerConfig.cs +++ b/Lite/Services/RemoteCollectorService.ServerConfig.cs @@ -336,6 +336,23 @@ FROM sys.databases AS d AND d.database_id < 32761 AND d.name <> N'PerformanceMonitor' AND d.state_desc = N'ONLINE' +AND d.database_id NOT IN + ( + SELECT + d2.database_id + FROM sys.databases AS d2 + JOIN sys.availability_replicas AS r + ON d2.replica_id = r.replica_id + WHERE NOT EXISTS + ( + SELECT + 1/0 + FROM sys.dm_hadr_availability_group_states AS s + WHERE s.primary_replica = r.replica_server_name + ) + AND r.secondary_role_allow_connections_desc = N'READ_ONLY' + AND r.replica_server_name = @@SERVERNAME + ) ORDER BY d.name OPTION(RECOMPILE);"; diff --git a/install/09_collect_query_store.sql b/install/09_collect_query_store.sql index a1cac83..7505695 100644 --- a/install/09_collect_query_store.sql +++ b/install/09_collect_query_store.sql @@ -291,6 +291,23 @@ BEGIN AND d.is_read_only = 0 AND d.name <> N'PerformanceMonitor' AND d.database_id < 32761 /*exclude contained AG system databases*/ + AND d.database_id NOT IN + ( + SELECT + d2.database_id + FROM sys.databases AS d2 + JOIN sys.availability_replicas AS r + ON d2.replica_id = r.replica_id + WHERE NOT EXISTS + ( + SELECT + 1/0 + FROM sys.dm_hadr_availability_group_states AS s + WHERE s.primary_replica = r.replica_server_name + ) + AND r.secondary_role_allow_connections_desc = N'READ_ONLY' + AND r.replica_server_name = @@SERVERNAME + ) OPTION(RECOMPILE); OPEN @db_check_cursor; diff --git a/install/39_collect_database_configuration.sql b/install/39_collect_database_configuration.sql index 199f155..1bac443 100644 --- a/install/39_collect_database_configuration.sql +++ b/install/39_collect_database_configuration.sql @@ -165,6 +165,23 @@ BEGIN AND d.name != DB_NAME() AND d.state_desc = N'ONLINE' AND d.database_id < 32761 /*exclude contained AG system databases*/ + AND d.database_id NOT IN + ( + SELECT + d2.database_id + FROM sys.databases AS d2 + JOIN sys.availability_replicas AS r + ON d2.replica_id = r.replica_id + WHERE NOT EXISTS + ( + SELECT + 1/0 + FROM sys.dm_hadr_availability_group_states AS s + WHERE s.primary_replica = r.replica_server_name + ) + AND r.secondary_role_allow_connections_desc = N'READ_ONLY' + AND r.replica_server_name = @@SERVERNAME + ) ORDER BY d.name OPTION (RECOMPILE);