Some checks failed
deploy community / deploy (push) Successful in 15s
deploy hub / deploy (push) Successful in 19s
CI / Build og unit tests (push) Successful in 7s
CI / MSI-installer (push) Successful in 17s
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Has been cancelled
Registers 1.3's SQL in SqlScriptSources (DatabaseDiscovery: databases 2005/2000 and the Dynamics AX signature per database; PermissionCheck: login/sysadmin, the HAS_PERMS_BY_NAME checks for 2005-2012, 2014-2019/MI and 2022+, databases without access) and adds _collectors/DatabaseDiscovery.sql and PermissionCheck.sql with Danish review headers. The constants are renamed *Sql and the login query moved to PermissionCheck.WhoSql so the registry test finds them. The scripts of the collectors that now skip unchosen databases say so (their SQL is unchanged). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
80 lines
5.1 KiB
Transact-SQL
80 lines
5.1 KiB
Transact-SQL
-- ===================================================================================================================
|
|
-- Collector: QueryStoreCollector ("query-store")
|
|
-- ===================================================================================================================
|
|
-- Hvad: Query Store i hver brugerdatabase, hvor det er slået til: de 100 tungeste queries over 8 dage og
|
|
-- forcerede planer, der fejler.
|
|
-- Fil: src/SQLInsight.Collectors/Performance/QueryStoreCollector.cs
|
|
-- Databaser: Fra 1.3 kun de databaser, der er valgt under Servere og databaser (systemdatabaserne altid; se
|
|
-- _collectors/DatabaseDiscovery.sql). Fravalgte databaser sorteres fra i koden efter forespørgslen; SQL'en er uændret.
|
|
-- Interval: 30 min som standard (SQLInsight:CollectorIntervals:query-store)
|
|
-- Versioner: SQL Server 2016 og nyere
|
|
--
|
|
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
|
-- GRANT VIEW SERVER STATE TO [agent]; -- SQL Server 2005-2019
|
|
-- GRANT VIEW SERVER PERFORMANCE STATE TO [agent]; -- SQL Server 2022+ (erstatter VIEW SERVER STATE)
|
|
-- GRANT VIEW SERVER SECURITY STATE TO [agent]; -- SQL Server 2022+
|
|
-- GRANT VIEW ANY DEFINITION TO [agent]; -- metadata; giver IKKE adgang til data
|
|
-- GRANT CONNECT ANY DATABASE TO [agent]; -- SQL Server 2014+; giver IKKE adgang til data
|
|
-- Før 2014 i stedet, i hver brugerdatabase: CREATE USER [agent] FOR LOGIN [agent];
|
|
--
|
|
-- Bruges af: SQLI-QS-001, SQLI-QS-002, SQLI-QS-003
|
|
-- Read-only: Ja: kun SELECT samt lokale variabler, SET-sessionsindstillinger. Intet ændrer data, indstillinger
|
|
-- eller objekter.
|
|
-- Kørsel: Kør i SSMS som agentens login. Hver variant er sin egen batch (GO); en variant for en anden SQL Server-version
|
|
-- end din kan fejle - det er forventet. Agenten kører altid med sessionsindstillingerne i _collectors/InstanceProbe.sql.
|
|
-- ===================================================================================================================
|
|
|
|
-- Variant: SQL Server 2016 og nyere
|
|
-- Kilde: QueryStoreCollector.DatabasesSql
|
|
-- Kode: src/SQLInsight.Collectors/Performance/QueryStoreCollector.cs : QueryStoreCollector.DatabasesSql
|
|
SELECT name FROM sys.databases
|
|
WHERE is_query_store_on = 1 AND state = 0 AND database_id > 4
|
|
GO
|
|
|
|
-- Variant: SQL Server 2016 og nyere: én gang pr. database med Query Store (vist for msdb)
|
|
-- Kilde: QueryStoreCollector.BuildStatsSql
|
|
-- Kode: src/SQLInsight.Collectors/Performance/QueryStoreCollector.cs : QueryStoreCollector.BuildStatsSql(database)
|
|
DECLARE @now datetimeoffset = SYSDATETIMEOFFSET();
|
|
DECLARE @recent datetimeoffset = DATEADD(hour, -24, @now);
|
|
DECLARE @history datetimeoffset = DATEADD(day, -8, @now);
|
|
|
|
WITH stats AS (
|
|
SELECT p.query_id, p.plan_id,
|
|
CASE WHEN i.start_time >= @recent THEN 1 ELSE 0 END AS is_recent,
|
|
SUM(rs.count_executions) AS execs,
|
|
SUM(rs.avg_duration * rs.count_executions) AS total_duration,
|
|
SUM(rs.avg_cpu_time * rs.count_executions) AS total_cpu,
|
|
SUM(rs.avg_logical_io_reads * rs.count_executions) AS total_reads,
|
|
MAX(rs.stdev_duration) AS max_stdev_duration,
|
|
MAX(rs.max_duration) AS max_duration,
|
|
MIN(rs.min_duration) AS min_duration,
|
|
MAX(rs.last_execution_time) AS last_execution
|
|
FROM [msdb].sys.query_store_runtime_stats rs
|
|
JOIN [msdb].sys.query_store_runtime_stats_interval i ON i.runtime_stats_interval_id = rs.runtime_stats_interval_id
|
|
JOIN [msdb].sys.query_store_plan p ON p.plan_id = rs.plan_id
|
|
WHERE i.start_time >= @history
|
|
GROUP BY p.query_id, p.plan_id, CASE WHEN i.start_time >= @recent THEN 1 ELSE 0 END
|
|
), top_queries AS (
|
|
SELECT TOP (100) query_id FROM stats GROUP BY query_id ORDER BY SUM(total_duration) DESC
|
|
)
|
|
SELECT s.query_id, s.plan_id, s.is_recent, s.execs, s.total_duration, s.total_cpu, s.total_reads,
|
|
s.max_stdev_duration, s.max_duration, s.min_duration,
|
|
CAST(SWITCHOFFSET(s.last_execution, '+00:00') AS datetime2(0)),
|
|
p.is_forced_plan, LEFT(qt.query_sql_text, 2000),
|
|
OBJECT_SCHEMA_NAME(q.object_id, DB_ID(N'msdb')) + N'.' + OBJECT_NAME(q.object_id, DB_ID(N'msdb'))
|
|
FROM stats s
|
|
JOIN top_queries t ON t.query_id = s.query_id
|
|
JOIN [msdb].sys.query_store_plan p ON p.plan_id = s.plan_id
|
|
JOIN [msdb].sys.query_store_query q ON q.query_id = s.query_id
|
|
JOIN [msdb].sys.query_store_query_text qt ON qt.query_text_id = q.query_text_id;
|
|
GO
|
|
|
|
-- Variant: SQL Server 2016 og nyere: én gang pr. database med Query Store (vist for msdb)
|
|
-- Kilde: QueryStoreCollector.BuildFailedForcedSql
|
|
-- Kode: src/SQLInsight.Collectors/Performance/QueryStoreCollector.cs : QueryStoreCollector.BuildFailedForcedSql(database)
|
|
SELECT p.query_id, p.plan_id, p.force_failure_count, p.last_force_failure_reason_desc, LEFT(qt.query_sql_text, 2000)
|
|
FROM [msdb].sys.query_store_plan p
|
|
JOIN [msdb].sys.query_store_query q ON q.query_id = p.query_id
|
|
JOIN [msdb].sys.query_store_query_text qt ON qt.query_text_id = q.query_text_id
|
|
WHERE p.is_forced_plan = 1 AND p.force_failure_count > 0;
|
|
GO
|