diff --git a/Lite/Services/RemoteCollectorService.QueryStore.cs b/Lite/Services/RemoteCollectorService.QueryStore.cs index 287983c0..737dd7ff 100644 --- a/Lite/Services/RemoteCollectorService.QueryStore.cs +++ b/Lite/Services/RemoteCollectorService.QueryStore.cs @@ -26,20 +26,69 @@ public partial class RemoteCollectorService /// private async Task CollectQueryStoreAsync(ServerConnection server, CancellationToken cancellationToken) { - /* First, get databases with Query Store enabled */ + /* First, get databases with Query Store actually enabled. + Uses sys.database_query_store_options.actual_state instead of + sys.databases.is_query_store_on, which can be out of sync on Azure SQL DB. */ const string dbQuery = @" +SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT /* PerformanceMonitorLite */ - d.name -FROM sys.databases AS d -WHERE d.is_query_store_on = 1 -AND d.database_id > 4 -AND d.database_id < 32761 -AND d.state_desc = N'ONLINE' -AND d.name <> N'PerformanceMonitor' -ORDER BY d.name -OPTION(RECOMPILE);"; +DECLARE + @result TABLE (name sysname); + +DECLARE + @db sysname, + @sql NVARCHAR(500); + +DECLARE db_check CURSOR LOCAL FAST_FORWARD FOR + SELECT /* PerformanceMonitorLite */ + d.name + FROM sys.databases AS d + WHERE d.database_id > 4 + AND d.database_id < 32761 + AND d.state_desc = N'ONLINE' + AND d.name <> N'PerformanceMonitor' + OPTION(RECOMPILE); + +OPEN db_check; + +FETCH NEXT +FROM db_check +INTO @db; + +WHILE @@FETCH_STATUS = 0 +BEGIN + BEGIN TRY + SET @sql = + N'USE ' + QUOTENAME(@db) + N'; + SELECT ' + QUOTENAME(@db, '''') + N' + WHERE EXISTS + ( + SELECT + 1 + FROM sys.database_query_store_options + WHERE actual_state > 0 + );'; + + INSERT @result (name) + EXEC(@sql); + END TRY + BEGIN CATCH + END CATCH; + + FETCH NEXT + FROM db_check + INTO @db; +END; + +CLOSE db_check; +DEALLOCATE db_check; + +SELECT + name +FROM @result +ORDER BY + name;"; var serverId = GetServerId(server); var collectionTime = DateTime.UtcNow; diff --git a/install/09_collect_query_store.sql b/install/09_collect_query_store.sql index 52608bf7..f8a13b20 100644 --- a/install/09_collect_query_store.sql +++ b/install/09_collect_query_store.sql @@ -265,17 +265,23 @@ BEGIN ); /* - Loop through databases where Query Store is enabled + Build list of databases where Query Store is actually enabled. + Uses sys.database_query_store_options.actual_state instead of + sys.databases.is_query_store_on, which can be out of sync on Azure SQL DB. */ DECLARE - @database_name sysname; - - DECLARE @database_cursor CURSOR - - SET @database_cursor = - CURSOR - LOCAL - FAST_FORWARD + @database_name sysname, + @qs_check_sql NVARCHAR(500); + + DECLARE + @qs_databases TABLE (name sysname); + + DECLARE @db_check_cursor CURSOR + + SET @db_check_cursor = + CURSOR + LOCAL + FAST_FORWARD FOR SELECT d.name @@ -283,15 +289,64 @@ BEGIN WHERE d.state_desc = N'ONLINE' AND d.database_id > 4 AND d.is_read_only = 0 - AND d.is_query_store_on = 1 AND d.name <> N'PerformanceMonitor' AND d.database_id < 32761 /*exclude contained AG system databases*/ OPTION(RECOMPILE); + OPEN @db_check_cursor; + + FETCH NEXT + FROM @db_check_cursor + INTO @database_name; + + WHILE @@FETCH_STATUS = 0 + BEGIN + BEGIN TRY + SET @qs_check_sql = + N'USE ' + QUOTENAME(@database_name) + N'; + SELECT ' + QUOTENAME(@database_name, '''') + N' + WHERE EXISTS + ( + SELECT + 1 + FROM sys.database_query_store_options + WHERE actual_state > 0 + );'; + + INSERT @qs_databases (name) + EXEC(@qs_check_sql); + END TRY + BEGIN CATCH + END CATCH; + + FETCH NEXT + FROM @db_check_cursor + INTO @database_name; + END; + + CLOSE @db_check_cursor; + DEALLOCATE @db_check_cursor; + + /* + Loop through databases where Query Store is enabled + */ + DECLARE @database_cursor CURSOR + + SET @database_cursor = + CURSOR + LOCAL + FAST_FORWARD + FOR + SELECT + q.name + FROM @qs_databases AS q + ORDER BY + q.name; + OPEN @database_cursor; - FETCH NEXT - FROM @database_cursor + FETCH NEXT + FROM @database_cursor INTO @database_name; WHILE @@FETCH_STATUS = 0