SQL Scripts: one reviewable script per rule
A DBA should be able to review every statement SQLInsight sends to a monitored server before granting it access. "SQL Scripts/<rule-id>.sql" holds, per rule (82 built-in, 16 community), a Danish header (what and why, how C# judges the data, thresholds with config keys, severity, exact GRANTs, versions, collector file and member) and the collector's SQL verbatim, every version variant as its own batch. "_collectors/<Collector>.sql" holds each collector's queries once. The only statement that is not strictly read-only is documented in the scripts: the deadlock collector's session temp table (#system_health). Inline SQL in the collectors moved to internal constants and Build*Sql methods (no text changed), so SqlScriptTests can check that the scripts still contain the SQL the code sends, that every rule has a script, that every collector query is registered, and that nothing writes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
28bd148691
commit
2284e7f082
143 changed files with 14230 additions and 56 deletions
|
|
@ -28,6 +28,7 @@ Warnings behandles som fejl, og .NET-analyzers kører på niveauet `latest-recom
|
|||
| `src/SQLInsight.Contracts` | Wire-kontrakt mellem agent og Hub |
|
||||
| `src/SQLInsight.Hub` | Centralt API til findings, PostgreSQL (Fase 3) |
|
||||
| `db/permissions` | Least-privilege-script til agentens login |
|
||||
| `SQL Scripts` | Ét script pr. regel med præcis den SQL, SQLInsight kører, til gennemgang af en DBA (se [SQL Scripts/README.md](SQL%20Scripts/README.md)) |
|
||||
| `tests/` | Unit og integrationstests |
|
||||
|
||||
## Sådan skriver du en regel
|
||||
|
|
@ -37,16 +38,18 @@ Warnings behandles som fejl, og .NET-analyzers kører på niveauet `latest-recom
|
|||
3. Et finding skal have **evidens** (de konkrete tal), **forklaring** (hvorfor det er et problem) og **anbefaling** (hvad man gør). Fix-scripts vises for brugeren og køres aldrig automatisk.
|
||||
4. Skriv unit tests for alle udfald: fundet, ikke fundet, grænseværdier og versioner, hvor reglen ikke kan måles.
|
||||
5. Registrér reglen i `BuiltInRules`.
|
||||
6. Tilføj `SQL Scripts/<id>.sql` med den danske header (hvad, vurdering, grænser, alvor, rettigheder, versioner, collector) og collectorens SQL, ordret og med en `-- Kilde:`-linje pr. variant. Brug en eksisterende fil som skabelon. `SqlScriptTests` fejler, hvis filen mangler, eller hvis SQL'en ikke længere er den, koden sender.
|
||||
|
||||
### Uden C#: community-regler
|
||||
|
||||
Mange regler kan skrives som en SQL-forespørgsel i en JSON-fil under `rules/community/`. De kræver ingen C# og kan afprøves direkte mod en instans med `SQLInsight.Agent rules test`. Se [docs/regler.md](docs/regler.md).
|
||||
Mange regler kan skrives som en SQL-forespørgsel i en JSON-fil under `rules/community/`. De kræver ingen C# og kan afprøves direkte mod en instans med `SQLInsight.Agent rules test`. Se [docs/regler.md](docs/regler.md). Også en community-regel skal have sin `SQL Scripts/<id>.sql` med forespørgslen ordret (se fx `SQL Scripts/COM-SEC-001.sql`).
|
||||
|
||||
## Queries mod overvågede servere
|
||||
|
||||
- De skal være **read-only** og kunne køre med rettighederne fra `db/permissions/grant-least-privilege.sql`. Kræver de mere, skal scriptet og `LeastPrivilegeTests` opdateres i samme ændring.
|
||||
- De skal være billige: ingen `DETAILED`-scans, grænser på antal rækker og intet, der kan tage låse på brugerdata.
|
||||
- Tjek, hvilke versioner DMV'en og kolonnerne findes i, og angiv det som capabilities.
|
||||
- Læg SQL'en i en `internal const` eller en `internal static Build…Sql`-metode i collectoren, ikke inline i `CollectAsync`, og registrér den i `tests/SQLInsight.Collectors.Tests/SqlScripts/SqlScriptSources.cs`. Opdatér `SQL Scripts/_collectors/<Collector>.sql` og regelfilerne, der bruger collectoren. `SqlScriptTests` fejler ellers.
|
||||
|
||||
## Commits
|
||||
|
||||
|
|
|
|||
74
SQL Scripts/COM-AX-001.sql
Normal file
74
SQL Scripts/COM-AX-001.sql
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-AX-001: Dynamics AX 3.0 er uden support fra Microsoft
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-AX-001
|
||||
-- Titel: Dynamics AX 3.0 er uden support fra Microsoft
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Dynamics AX 3.0 er uden support fra Microsoft. Microsoft Dynamics AX 3.0 er for længst ude af Microsofts support,
|
||||
-- også den udvidede. Der kommer ingen sikkerhedsopdateringer eller rettelser til AX-kernen, klienten eller AOS, og
|
||||
-- nyere Windows- og SQL Server-versioner er aldrig testet med AX 3.0. AX 3.0 bruger desuden 32-bit RecId (int), som
|
||||
-- kan løbe tør på store installationer.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel: "{database}
|
||||
-- er en Dynamics AX 3.0-database, og AX 3.0 er uden support" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/dynamics-ax.json (id COM-AX-001, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-AX-001 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)) AS [sql_version] WHERE EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SQLDICTIONARY') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'DATAAREA') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SYSCONFIG') AND COLUMNPROPERTY((SELECT TOP 1 object_id FROM sys.tables WHERE name = N'SQLDICTIONARY'), N'RECID', 'Precision') = 10
|
||||
GO
|
||||
75
SQL Scripts/COM-AX-002.sql
Normal file
75
SQL Scripts/COM-AX-002.sql
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-AX-002: Dynamics AX 3.0 kører på en SQL Server-version, der ikke var understøttet til AX 3.0
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-AX-002
|
||||
-- Titel: Dynamics AX 3.0 kører på en SQL Server-version, der ikke var understøttet til AX 3.0
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Dynamics AX 3.0 kører på en SQL Server-version, der ikke var understøttet til AX 3.0. AX 3.0 blev kun frigivet
|
||||
-- til SQL Server 2000 og 2005. På nyere versioner kan den virke, men optimizeren, låsning og udfasede funktioner
|
||||
-- opfører sig anderledes end det, AX-kernen blev bygget til, og hverken Microsoft eller en AX-partner kan give
|
||||
-- support. Fejl viser sig ofte først under belastning, fx ved månedsafslutning. Databasens compatibility level er
|
||||
-- {compatibility_level}.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel: "AX
|
||||
-- 3.0-databasen {database} ligger på SQL Server {sql_version}" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/dynamics-ax.json (id COM-AX-002, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-AX-002 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)) AS [sql_version], d.compatibility_level AS [compatibility_level] FROM sys.databases d WHERE d.database_id = DB_ID() AND CAST(PARSENAME(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)), 4) AS int) > 9 AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SQLDICTIONARY') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'DATAAREA') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SYSCONFIG') AND COLUMNPROPERTY((SELECT TOP 1 object_id FROM sys.tables WHERE name = N'SQLDICTIONARY'), N'RECID', 'Precision') = 10
|
||||
GO
|
||||
74
SQL Scripts/COM-AX-003.sql
Normal file
74
SQL Scripts/COM-AX-003.sql
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-AX-003: Dynamics AX-database på en instans, hvor MAXDOP ikke er 1 (SQL Server 2005-2014)
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-AX-003
|
||||
-- Titel: Dynamics AX-database på en instans, hvor MAXDOP ikke er 1 (SQL Server 2005-2014)
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Dynamics AX-database på en instans, hvor MAXDOP ikke er 1 (SQL Server 2005-2014). Dynamics AX sender mange små,
|
||||
-- hyppige forespørgsler og cursorer fra AOS. Når de får parallelle planer, bruger de flere tråde end nødvendigt,
|
||||
-- venter på hinanden (CXPACKET) og holder låse længere, så brugerne oplever langsomme formularer og blokering.
|
||||
-- Microsofts vejledning for Dynamics AX er derfor max degree of parallelism = 1 på instansen.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel: "MAXDOP er
|
||||
-- {maxdop} på instansen med Dynamics AX-databasen {database}" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/dynamics-ax.json (id COM-AX-003, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-AX-003 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT CAST(c.value_in_use AS int) AS [maxdop] FROM sys.configurations c WHERE c.name = 'max degree of parallelism' AND CAST(c.value_in_use AS int) <> 1 AND CAST(PARSENAME(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)), 4) AS int) < 13 AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SQLDICTIONARY') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'DATAAREA') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SYSCONFIG')
|
||||
GO
|
||||
74
SQL Scripts/COM-AX-004.sql
Normal file
74
SQL Scripts/COM-AX-004.sql
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-AX-004: Dynamics AX-database, hvor MAXDOP ikke er 1 (SQL Server 2016 og nyere)
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-AX-004
|
||||
-- Titel: Dynamics AX-database, hvor MAXDOP ikke er 1 (SQL Server 2016 og nyere)
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2016 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Dynamics AX-database, hvor MAXDOP ikke er 1 (SQL Server 2016 og nyere). Dynamics AX sender mange små, hyppige
|
||||
-- forespørgsler og cursorer fra AOS. Når de får parallelle planer, bruger de flere tråde end nødvendigt, venter på
|
||||
-- hinanden (CXPACKET) og holder låse længere. Microsofts vejledning for Dynamics AX er MAXDOP 1. Instansen har
|
||||
-- {server_maxdop}, og databasen har {database_maxdop} (0 = instansens værdi gælder).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel: "Dynamics
|
||||
-- AX-databasen {database} kører med MAXDOP større end 1" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/dynamics-ax.json (id COM-AX-004, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-AX-004 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT CAST(c.value_in_use AS int) AS [server_maxdop], CAST(s.value AS int) AS [database_maxdop] FROM sys.configurations c CROSS JOIN sys.database_scoped_configurations s WHERE c.name = 'max degree of parallelism' AND s.name = 'MAXDOP' AND (CASE WHEN CAST(s.value AS int) = 0 THEN CAST(c.value_in_use AS int) ELSE CAST(s.value AS int) END) <> 1 AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SQLDICTIONARY') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'DATAAREA') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SYSCONFIG')
|
||||
GO
|
||||
74
SQL Scripts/COM-AX-005.sql
Normal file
74
SQL Scripts/COM-AX-005.sql
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-AX-005: Dynamics AX-tabeller uden unikt RecId-indeks
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-AX-005
|
||||
-- Titel: Dynamics AX-tabeller uden unikt RecId-indeks
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Dynamics AX-tabeller uden unikt RecId-indeks. AX identificerer hver post med RecId og opretter normalt et unikt
|
||||
-- indeks på den (I_<tabel-id>RECID) ved synkronisering. Mangler det, er en synkronisering typisk fejlet eller
|
||||
-- afbrudt, eller indekset er fjernet manuelt. Uden det bliver opslag på RecId (som AX laver hele tiden, fx ved
|
||||
-- opdatering og sletning af én post) til scanninger, og dubletter opdages ikke. Eksempler: {examples}.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel: "{tables}
|
||||
-- AX-tabeller i {database} har intet unikt indeks på RECID" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/dynamics-ax.json (id COM-AX-005, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-AX-005 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT COUNT(*) AS [tables], LEFT(STUFF((SELECT TOP 10 N', ' + t2.name FROM sys.tables t2 WHERE COLUMNPROPERTY(t2.object_id, N'RECID', 'ColumnId') IS NOT NULL AND NOT EXISTS (SELECT 1 FROM sys.indexes i JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0 JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id WHERE i.object_id = t2.object_id AND i.is_unique = 1 AND c.name = N'RECID') ORDER BY t2.name FOR XML PATH('')), 1, 2, ''), 400) AS [examples] FROM sys.tables t WHERE COLUMNPROPERTY(t.object_id, N'RECID', 'ColumnId') IS NOT NULL AND NOT EXISTS (SELECT 1 FROM sys.indexes i JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0 JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id WHERE i.object_id = t.object_id AND i.is_unique = 1 AND c.name = N'RECID') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SQLDICTIONARY') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'DATAAREA') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SYSCONFIG') HAVING COUNT(*) > 0
|
||||
GO
|
||||
74
SQL Scripts/COM-AX-006.sql
Normal file
74
SQL Scripts/COM-AX-006.sql
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-AX-006: Store Dynamics AX-tabeller uden clustered index (heaps)
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-AX-006
|
||||
-- Titel: Store Dynamics AX-tabeller uden clustered index (heaps)
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Store Dynamics AX-tabeller uden clustered index (heaps). En tabel uden clustered index (en heap) får spredte data
|
||||
-- og 'forwarded records', når poster opdateres, og den kan ikke defragmenteres med en indeks-rebuild. I AX styres
|
||||
-- det af tabellens ClusterIndex-egenskab i AOT, som i AX 3.0 ofte ikke er sat på standard- og kundetabeller. På
|
||||
-- store tabeller giver det langsomme opslag og mere I/O. I alt {rows} rækker. Største: {largest}.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel: "{tables}
|
||||
-- store AX-tabeller i {database} har intet clustered index" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/dynamics-ax.json (id COM-AX-006, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-AX-006 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT COUNT(*) AS [tables], SUM(h.row_count) AS [rows], LEFT(STUFF((SELECT TOP 10 N', ' + OBJECT_NAME(h2.object_id) + N' (' + CAST(h2.row_count AS nvarchar(20)) + N')' FROM (SELECT p.object_id, SUM(p.rows) AS row_count FROM sys.partitions p JOIN sys.tables t ON t.object_id = p.object_id WHERE p.index_id = 0 GROUP BY p.object_id) h2 WHERE h2.row_count >= 100000 ORDER BY h2.row_count DESC FOR XML PATH('')), 1, 2, ''), 400) AS [largest] FROM (SELECT p.object_id, SUM(p.rows) AS row_count FROM sys.partitions p JOIN sys.tables t ON t.object_id = p.object_id WHERE p.index_id = 0 GROUP BY p.object_id) h WHERE h.row_count >= 100000 AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SQLDICTIONARY') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'DATAAREA') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SYSCONFIG') HAVING COUNT(*) > 0
|
||||
GO
|
||||
75
SQL Scripts/COM-AX-007.sql
Normal file
75
SQL Scripts/COM-AX-007.sql
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-AX-007: Automatiske statistikker er slået fra i en Dynamics AX-database
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-AX-007
|
||||
-- Titel: Automatiske statistikker er slået fra i en Dynamics AX-database
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Automatiske statistikker er slået fra i en Dynamics AX-database. AX bygger sine forespørgsler dynamisk ud fra
|
||||
-- brugernes filtre, så optimizeren er helt afhængig af, at statistikkerne er der og er opdaterede. Uden automatiske
|
||||
-- statistikker vælger SQL Server ofte forkerte planer, især efter store kørsler som lageropgørelse og nummerserier,
|
||||
-- og formularer og batchjob kan pludselig blive meget langsomme. Auto create statistics: {auto_create_statistics}.
|
||||
-- Auto update statistics: {auto_update_statistics}.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel: "Automatiske
|
||||
-- statistikker er slået fra i AX-databasen {database}" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/dynamics-ax.json (id COM-AX-007, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-AX-007 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT CASE WHEN d.is_auto_create_stats_on = 1 THEN 'til' ELSE 'fra' END AS [auto_create_statistics], CASE WHEN d.is_auto_update_stats_on = 1 THEN 'til' ELSE 'fra' END AS [auto_update_statistics] FROM sys.databases d WHERE d.database_id = DB_ID() AND (d.is_auto_create_stats_on = 0 OR d.is_auto_update_stats_on = 0) AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SQLDICTIONARY') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'DATAAREA') AND EXISTS (SELECT 1 FROM sys.tables WHERE name = N'SYSCONFIG')
|
||||
GO
|
||||
62
SQL Scripts/COM-CFG-001.sql
Normal file
62
SQL Scripts/COM-CFG-001.sql
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-CFG-001: Default trace er slået fra
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-CFG-001
|
||||
-- Titel: Default trace er slået fra
|
||||
-- Alvor: Low
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Default trace er slået fra. Default trace er en let sporing, der registrerer bl.a. autogrowth, ændringer af
|
||||
-- objekter og logins. Uden den er det svært at efterforske, hvad der skete, efter en hændelse.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres én gang i master. Kører instansen en ældre version end minimumVersion, er reglen
|
||||
-- "ikke relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel:
|
||||
-- "Default trace er slået fra" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- GRANT VIEW ANY DEFINITION TO [agent]; -- metadata; giver IKKE adgang til data
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/security.json (id COM-CFG-001, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-CFG-001 (server-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
USE [master];
|
||||
SELECT CAST(value_in_use AS int) AS [value_in_use] FROM sys.configurations WHERE name = 'default trace enabled' AND value_in_use = 0
|
||||
GO
|
||||
73
SQL Scripts/COM-DB-001.sql
Normal file
73
SQL Scripts/COM-DB-001.sql
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-DB-001: Fremmednøgler, som SQL Server ikke stoler på
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-DB-001
|
||||
-- Titel: Fremmednøgler, som SQL Server ikke stoler på
|
||||
-- Alvor: Low
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Fremmednøgler, som SQL Server ikke stoler på. Nøglen er blevet slået til igen uden WITH CHECK, fx efter en
|
||||
-- dataindlæsning. Den håndhæves for nye rækker, men SQL Server kan ikke stole på eksisterende data, så optimizeren
|
||||
-- udnytter den ikke til at fjerne joins, og der kan ligge ugyldige data.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel: "{database}:
|
||||
-- fremmednøglen {constraint} på {table} er ikke betroet" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/integrity.json (id COM-DB-001, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-DB-001 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT s.name + '.' + o.name AS [table], fk.name AS [constraint] FROM sys.foreign_keys fk JOIN sys.objects o ON o.object_id = fk.parent_object_id JOIN sys.schemas s ON s.schema_id = o.schema_id WHERE fk.is_not_trusted = 1 AND fk.is_disabled = 0
|
||||
GO
|
||||
73
SQL Scripts/COM-FT-001.sql
Normal file
73
SQL Scripts/COM-FT-001.sql
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-FT-001: Fulltext-katalog er sat på pause, fordi disken er fuld
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-FT-001
|
||||
-- Titel: Fulltext-katalog er sat på pause, fordi disken er fuld
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Fulltext-katalog er sat på pause, fordi disken er fuld. SQL Server har sat opbygningen af fulltext-kataloget
|
||||
-- {catalog} på pause, fordi der ikke er plads på disken. Søgninger med CONTAINS og FREETEXT bruger det indeks, der
|
||||
-- var bygget, så nye og ændrede rækker findes ikke. Det fortsætter ikke af sig selv, før der er plads.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel:
|
||||
-- "Fulltext-kataloget {catalog} i {database} er stoppet: disken er fuld" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/fulltext.json (id COM-FT-001, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-FT-001 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT c.name AS [catalog], FULLTEXTCATALOGPROPERTY(c.name, 'ItemCount') AS [items] FROM sys.fulltext_catalogs c WHERE FULLTEXTCATALOGPROPERTY(c.name, 'PopulateStatus') = 8
|
||||
GO
|
||||
73
SQL Scripts/COM-FT-002.sql
Normal file
73
SQL Scripts/COM-FT-002.sql
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-FT-002: Fulltext-katalog er sat på pause eller drosles
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-FT-002
|
||||
-- Titel: Fulltext-katalog er sat på pause eller drosles
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Fulltext-katalog er sat på pause eller drosles. Opbygningen af fulltext-kataloget {catalog} er {status}. Mens den
|
||||
-- står stille, finder fulltext-søgninger ikke nye og ændrede rækker. 'Droslet' betyder, at SQL Server har bremset
|
||||
-- opbygningen på grund af ressourcemangel (hukommelse eller CPU); 'pause' kan være sat manuelt eller af SQL Server.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel:
|
||||
-- "Fulltext-kataloget {catalog} i {database} er {status}" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/fulltext.json (id COM-FT-002, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-FT-002 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT c.name AS [catalog], CASE FULLTEXTCATALOGPROPERTY(c.name, 'PopulateStatus') WHEN 2 THEN 'sat på pause' ELSE 'droslet' END AS [status] FROM sys.fulltext_catalogs c WHERE FULLTEXTCATALOGPROPERTY(c.name, 'PopulateStatus') IN (2, 3)
|
||||
GO
|
||||
73
SQL Scripts/COM-FT-003.sql
Normal file
73
SQL Scripts/COM-FT-003.sql
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-FT-003: Fulltext-indeks uden automatisk opdatering er ikke opdateret i over en uge
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-FT-003
|
||||
-- Titel: Fulltext-indeks uden automatisk opdatering er ikke opdateret i over en uge
|
||||
-- Alvor: Low
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Fulltext-indeks uden automatisk opdatering er ikke opdateret i over en uge. Fulltext-indekset på {table}
|
||||
-- opdateres ikke automatisk (change tracking er {change_tracking}), og kataloget {catalog} blev sidst bygget
|
||||
-- {last_population}. Søgninger finder ikke rækker, der er oprettet eller ændret siden.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel:
|
||||
-- "Fulltext-indekset på {table} i {database} er sidst opdateret {last_population}" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/fulltext.json (id COM-FT-003, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-FT-003 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT OBJECT_NAME(i.object_id) AS [table], c.name AS [catalog], CASE i.change_tracking_state WHEN 'M' THEN 'manuel' ELSE 'slået fra' END AS [change_tracking], CONVERT(varchar(16), DATEADD(second, FULLTEXTCATALOGPROPERTY(c.name, 'PopulateCompletionAge'), '19900101'), 120) AS [last_population] FROM sys.fulltext_indexes i JOIN sys.fulltext_catalogs c ON c.fulltext_catalog_id = i.fulltext_catalog_id WHERE i.change_tracking_state IN ('M', 'O') AND i.is_enabled = 1 AND FULLTEXTCATALOGPROPERTY(c.name, 'PopulateCompletionAge') > 0 AND DATEADD(second, FULLTEXTCATALOGPROPERTY(c.name, 'PopulateCompletionAge'), '19900101') < DATEADD(day, -7, GETDATE()) AND DATEADD(second, FULLTEXTCATALOGPROPERTY(c.name, 'PopulateCompletionAge'), '19900101') >= DATEADD(day, -30, GETDATE())
|
||||
GO
|
||||
74
SQL Scripts/COM-FT-004.sql
Normal file
74
SQL Scripts/COM-FT-004.sql
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-FT-004: Fulltext-indeks uden automatisk opdatering er ikke opdateret i over 30 dage
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-FT-004
|
||||
-- Titel: Fulltext-indeks uden automatisk opdatering er ikke opdateret i over 30 dage
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Fulltext-indeks uden automatisk opdatering er ikke opdateret i over 30 dage. Fulltext-indekset på {table}
|
||||
-- opdateres ikke automatisk (change tracking er {change_tracking}), og kataloget {catalog} er ikke bygget i over 30
|
||||
-- dage (sidst {last_population}). Søgninger med CONTAINS og FREETEXT giver derfor forældede resultater.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel:
|
||||
-- "Fulltext-indekset på {table} i {database} er ikke opdateret siden {last_population}" ({kolonne} udfyldes fra
|
||||
-- rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/fulltext.json (id COM-FT-004, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-FT-004 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT OBJECT_NAME(i.object_id) AS [table], c.name AS [catalog], CASE i.change_tracking_state WHEN 'M' THEN 'manuel' ELSE 'slået fra' END AS [change_tracking], CONVERT(varchar(16), DATEADD(second, FULLTEXTCATALOGPROPERTY(c.name, 'PopulateCompletionAge'), '19900101'), 120) AS [last_population] FROM sys.fulltext_indexes i JOIN sys.fulltext_catalogs c ON c.fulltext_catalog_id = i.fulltext_catalog_id WHERE i.change_tracking_state IN ('M', 'O') AND i.is_enabled = 1 AND FULLTEXTCATALOGPROPERTY(c.name, 'PopulateCompletionAge') > 0 AND DATEADD(second, FULLTEXTCATALOGPROPERTY(c.name, 'PopulateCompletionAge'), '19900101') < DATEADD(day, -30, GETDATE())
|
||||
GO
|
||||
72
SQL Scripts/COM-FT-005.sql
Normal file
72
SQL Scripts/COM-FT-005.sql
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-FT-005: Fulltext-indeks er deaktiveret
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-FT-005
|
||||
-- Titel: Fulltext-indeks er deaktiveret
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Fulltext-indeks er deaktiveret. Fulltext-indekset på {table} (kataloget {catalog}) er slået fra. Det opdateres
|
||||
-- ikke, og fulltext-søgninger mod tabellen fejler eller finder intet, afhængigt af hvordan applikationen søger.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres i hver online brugerdatabase, agenten kan åbne (CustomQueryCollector.DatabasesSql),
|
||||
-- og kolonnen database tilføjes hver række. Kører instansen en ældre version end minimumVersion, er reglen "ikke
|
||||
-- relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel:
|
||||
-- "Fulltext-indekset på {table} i {database} er deaktiveret" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/fulltext.json (id COM-FT-005, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-FT-005 (database-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Databaserne, reglen køres i
|
||||
-- Kilde: CustomQueryCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.DatabasesSql
|
||||
SELECT name FROM sys.databases WHERE database_id > 4 AND state = 0 AND source_database_id IS NULL AND HAS_DBACCESS(name) = 1 ORDER BY name
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Agenten kører dette i hver brugerdatabase fra listen ovenfor. Ret [msdb] til den database, du vil tjekke.
|
||||
USE [msdb];
|
||||
SELECT OBJECT_NAME(i.object_id) AS [table], c.name AS [catalog] FROM sys.fulltext_indexes i JOIN sys.fulltext_catalogs c ON c.fulltext_catalog_id = i.fulltext_catalog_id WHERE i.is_enabled = 0
|
||||
GO
|
||||
62
SQL Scripts/COM-SEC-001.sql
Normal file
62
SQL Scripts/COM-SEC-001.sql
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-SEC-001: Login'et sa er aktivt
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-SEC-001
|
||||
-- Titel: Login'et sa er aktivt
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Login'et sa er aktivt. sa er det login, angribere prøver først, fordi navnet er kendt, og det har fulde
|
||||
-- rettigheder. Password-politik håndhæves: {password_policy}.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres én gang i master. Kører instansen en ældre version end minimumVersion, er reglen
|
||||
-- "ikke relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel: "Det
|
||||
-- indbyggede login '{login}' er aktivt" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- GRANT VIEW ANY DEFINITION TO [agent]; -- metadata; giver IKKE adgang til data
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/security.json (id COM-SEC-001, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-SEC-001 (server-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
USE [master];
|
||||
SELECT name AS [login], CASE WHEN is_policy_checked = 1 THEN 'ja' ELSE 'nej' END AS [password_policy] FROM sys.sql_logins WHERE principal_id = 1 AND is_disabled = 0
|
||||
GO
|
||||
63
SQL Scripts/COM-SEC-002.sql
Normal file
63
SQL Scripts/COM-SEC-002.sql
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
-- ===================================================================================================================
|
||||
-- COM-SEC-002: Database ejes af et login, der ikke findes
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: COM-SEC-002
|
||||
-- Titel: Database ejes af et login, der ikke findes
|
||||
-- Alvor: Low
|
||||
-- Versioner: SQL Server 2008 og nyere. Kræver ingen særlige capabilities (DeclarativeRule).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Database ejes af et login, der ikke findes. Ejeren er typisk en medarbejder, som er stoppet, eller en database,
|
||||
-- der er gendannet fra en anden server. Det giver fejl i fx EXECUTE AS OWNER, cross-database ownership chaining og
|
||||
-- nogle jobs.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ingen C#-logik ud over at læse resultatet: hver række, forespørgslen returnerer, er et fund (højst 100 rækker pr.
|
||||
-- regel). Forespørgslen køres én gang i master. Kører instansen en ældre version end minimumVersion, er reglen
|
||||
-- "ikke relevant". Fejler forespørgslen pga. manglende rettigheder, er reglen "ikke målbar". Fundets titel:
|
||||
-- "Databasen {database} ejes af et login, der ikke længere findes" ({kolonne} udfyldes fra rækken).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: eventuelle grænser står direkte i forespørgslen (fx antal rækker eller dage).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- GRANT VIEW ANY DEFINITION TO [agent]; -- metadata; giver IKKE adgang til data
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CustomQueryCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs
|
||||
-- Medlemmer: Db.CurrentDatabaseSql, CustomQueryCollector.DatabasesSql,
|
||||
-- CustomQueryCollector.BuildRuleSql(database, query)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:custom-rules)
|
||||
-- Delt script: SQL Scripts/_collectors/CustomQueryCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Custom/DeclarativeRule.cs : DeclarativeRule.Evaluate; reglen selv:
|
||||
-- rules/community/security.json (id COM-SEC-002, indlejret i regelpakken)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: Community-regel COM-SEC-002 (server-regel)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere
|
||||
-- Kilde: CustomQueryCollector.BuildRuleSql
|
||||
-- Kode: src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs : CustomQueryCollector.BuildRuleSql(database, query)
|
||||
USE [master];
|
||||
SELECT d.name AS [database], CONVERT(varchar(100), d.owner_sid, 1) AS [owner_sid] FROM sys.databases d LEFT JOIN sys.server_principals p ON p.sid = d.owner_sid WHERE p.sid IS NULL AND d.database_id > 4
|
||||
GO
|
||||
230
SQL Scripts/README.md
Normal file
230
SQL Scripts/README.md
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
# SQL Scripts
|
||||
|
||||
Denne mappe indeholder **præcis den SQL, SQLInsight Pro kører mod en overvåget SQL Server**, ordnet efter regel. Den er
|
||||
lavet, så en DBA kan gennemgå hver eneste sætning, før agenten får adgang til en server: hvad der læses, med hvilke
|
||||
rettigheder, på hvilke versioner, og hvordan reglen bagefter vurderer data.
|
||||
|
||||
Agenten kører **ikke** filerne her. De er en læsbar kopi af SQL'en i koden, og unit tests sikrer, at kopien er
|
||||
identisk med koden (se [Hold mappen i sync](#hold-mappen-i-sync)).
|
||||
|
||||
## Navngivning
|
||||
|
||||
| Fil | Indhold |
|
||||
|---|---|
|
||||
| `<regel-id>.sql` | Én fil pr. regel, navngivet med regel-id'et præcis som i systemet: `SQLI-…` for de indbyggede regler (C#), `COM-…` for community-regler (JSON i `rules/community/`). |
|
||||
| `_collectors/<Collector>.sql` | Alle forespørgsler fra én collector. Flere regler deler ofte samme collector; regelfilerne gentager SQL'en, så hver fil kan køres for sig. |
|
||||
| `_collectors/InstanceProbe.sql` | Registreringen af instansen (version, udgave, Always On) og de sessionsindstillinger, agenten sætter på hver forbindelse. |
|
||||
|
||||
## Opbygning af en regelfil
|
||||
|
||||
Hver fil starter med en kommentar-header på dansk:
|
||||
|
||||
- **Regel-id, titel, alvor (severity)** og **understøttede versioner**.
|
||||
- **Hvad tjekkes, og hvorfor.**
|
||||
- **Vurdering**: de fleste regler afgør ikke selv noget i SQL. Collectoren læser data, og reglen vurderer dem i C#
|
||||
(fx "fund hvis ventetiden er over 5 ms i gennemsnit mellem to målinger"). Logikken er beskrevet i almindeligt dansk.
|
||||
- **Grænseværdier** med konfigurationsnøgle (i agentens `appsettings.json`, sektionen `SQLInsight`) og standardværdi, eller
|
||||
"fast i koden".
|
||||
- **Rettigheder** som præcise `GRANT`-sætninger (`[agent]` = agentens login), svarende til
|
||||
`db/permissions/grant-least-privilege.sql`.
|
||||
- **Data kommer fra**: collectoren, kildefilen og konstanten/metoden, der indeholder SQL'en, samt intervallet.
|
||||
- **Regelkode**: filen og klassen, der vurderer data.
|
||||
- **Read-only**: hvad scriptet gør ud over SELECT.
|
||||
|
||||
Derefter følger SQL'en, én blok pr. variant:
|
||||
|
||||
```sql
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT ...
|
||||
GO
|
||||
```
|
||||
|
||||
- `Variant` siger, hvilke versioner (eller hvilken situation) teksten sendes for. Agenten vælger varianten ud fra
|
||||
instansens version og capabilities.
|
||||
- `Kilde` er nøglen, som testen bruger til at sammenligne med koden.
|
||||
- `Kode` er stedet i koden, hvor SQL'en står eller bygges.
|
||||
|
||||
## Sådan køres scriptene
|
||||
|
||||
1. Åbn filen i SQL Server Management Studio (eller kør `sqlcmd -i "SQL Scripts\SQLI-DB-007.sql"`).
|
||||
2. Forbind **som agentens login** (fx gMSA'en), eller et login med præcis de rettigheder, `grant-least-privilege.sql`
|
||||
giver. Som sysadmin virker alt, men så ser man ikke, om en rettighed mangler.
|
||||
3. Kør hele filen. Første batch sætter de samme sessionsindstillinger som agenten:
|
||||
`SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;`
|
||||
4. Varianter for andre SQL Server-versioner end din kan fejle (fx SQL Server 2000-varianten mod `master.dbo.sysaltfiles`
|
||||
eller kolonner, der først findes i nyere versioner). Det er forventet; SSMS fortsætter med næste batch.
|
||||
|
||||
Bemærk:
|
||||
|
||||
- **Read-only.** Alle scripts læser kun: SELECT mod katalog-views og DMV'er, `DBCC TRACESTATUS`, `DBCC SQLPERF(WAITSTATS)`
|
||||
(kun SQL Server 2000), `xp_readerrorlog`, `xp_msver`, `sys.fn_trace_gettable`, lokale variabler og `USE`.
|
||||
**Én undtagelse:** `SQLI-DLK-001` / `_collectors/DeadlockCollector.sql` (SQL Server 2012+) opretter en midlertidig
|
||||
tabel `#system_health` i tempdb og sletter den igen i samme batch. Den er privat for sessionen, og ingen brugerdata,
|
||||
indstillinger eller permanente objekter ændres, men det er strengt taget en skrivning i tempdb. Det står også i
|
||||
filernes header.
|
||||
- **Per-database-forespørgsler** (indexes, statistikker, Query Store, database-scoped community-regler) kører agenten i
|
||||
hver online brugerdatabase. Her er de vist for `msdb`, som findes på alle instanser, så scriptet kan køres uændret.
|
||||
Ret `[msdb]` / `N'msdb'` til den database, du vil se.
|
||||
- **Værdier, agenten beregner ved kørsel** (default trace-filens sti, tidspunktet for forrige måling) er erstattet af
|
||||
variabler, der erklæres lige over forespørgslen med realistiske standardværdier. Kommentaren over viser, hvad agenten
|
||||
indsætter. Grænser fra konfigurationen (fx 1024 MB log, 15 minutter) er vist med standardværdien.
|
||||
- **Ikke med her:** fix-scripts i fundene (de vises for brugeren og køres aldrig automatisk), agentens eget repository
|
||||
(fx baseline-historikken bag `SQLI-ANOM-001`, som ikke hentes fra den overvågede server) og kundens lokale regler
|
||||
(`LOCAL-…`).
|
||||
|
||||
## Hold mappen i sync
|
||||
|
||||
`tests/SQLInsight.Collectors.Tests/SqlScripts/SqlScriptTests.cs` fejler, hvis mappen og koden ikke stemmer overens:
|
||||
|
||||
- `Every_registered_rule_has_a_script_and_every_script_a_rule`: hver indbygget regel (`BuiltInRules`) og hver
|
||||
community-regel i regelpakken har en `<id>.sql`, og der er ingen filer for ukendte id'er.
|
||||
- `Scripts_contain_the_current_sql_from_the_code`: hver blok med `-- Kilde: <nøgle>` indeholder SQL'en, som koden
|
||||
bygger den i dag, ordret (nøglerne står i `SqlScriptSources.cs`). Kun værdier, agenten beregner ved kørsel, må stå
|
||||
anderledes.
|
||||
- `Every_collector_query_is_registered_and_in_a_collector_script`: hver SQL-konstant og hver `Build…Sql`-metode i
|
||||
collectorerne er registreret, og hver registreret forespørgsel står i et `_collectors/`-script.
|
||||
- `Community_rule_scripts_contain_the_rule_query_verbatim`: community-reglens `query` fra JSON står ordret i filen.
|
||||
- `Scripts_are_read_only_apart_from_the_documented_temp_table`: ingen skrivende sætninger ud over undtagelsen ovenfor.
|
||||
|
||||
En ny regel skal derfor have sin `SQL Scripts/<id>.sql` (se `CONTRIBUTING.md`). Ændres en collectors SQL, peger
|
||||
testen på de filer, der skal opdateres.
|
||||
|
||||
## Regler
|
||||
|
||||
98 regler: 82 indbyggede (C#) og 16 community-regler (JSON).
|
||||
|
||||
| Regel-id | Fil | Titel | Collector(s) | Alvor |
|
||||
|---|---|---|---|---|
|
||||
| SQLI-AG-001 | [SQLI-AG-001.sql](SQLI-AG-001.sql) | Always On availability group er ikke sund | AvailabilityGroupCollector | High for DISCONNECTED, NOT_HEALTHY og suspenderet; Medium for PARTIALLY_HEALTHY. |
|
||||
| SQLI-AG-002 | [SQLI-AG-002.sql](SQLI-AG-002.sql) | Sekundær replika er langt bagud | AvailabilityGroupCollector | Medium |
|
||||
| SQLI-AG-003 | [SQLI-AG-003.sql](SQLI-AG-003.sql) | En node eller et vidne i clusteret er nede | AvailabilityGroupCollector | High |
|
||||
| SQLI-ANOM-001 | [SQLI-ANOM-001.sql](SQLI-ANOM-001.sql) | Usædvanlig belastning i forhold til det normale | CpuCollector, PerformanceCounterCollector | CPU: Medium. Batch requests: Low ved stigning, Medium ved fald. Page life expectancy: Medium. |
|
||||
| SQLI-BLK-001 | [SQLI-BLK-001.sql](SQLI-BLK-001.sql) | Langvarig blocking | BlockingCollector | Medium; High når længste ventetid er mindst 5 minutter eller mindst 10 sessioner er blokeret. |
|
||||
| SQLI-CFG-001 | [SQLI-CFG-001.sql](SQLI-CFG-001.sql) | max server memory er ikke sat | ConfigurationCollector, ServerCollector | High |
|
||||
| SQLI-CFG-002 | [SQLI-CFG-002.sql](SQLI-CFG-002.sql) | max server memory efterlader for lidt til Windows | ConfigurationCollector, ServerCollector | Medium |
|
||||
| SQLI-CFG-003 | [SQLI-CFG-003.sql](SQLI-CFG-003.sql) | cost threshold for parallelism står på standardværdien 5 | ConfigurationCollector, ServerCollector | Medium |
|
||||
| SQLI-CFG-004 | [SQLI-CFG-004.sql](SQLI-CFG-004.sql) | MAXDOP passer ikke til serverens NUMA-layout | ConfigurationCollector, ServerCollector | Medium |
|
||||
| SQLI-CFG-005 | [SQLI-CFG-005.sql](SQLI-CFG-005.sql) | Plan cache er fyldt med engangsplaner | ConfigurationCollector, PlanCacheCollector | Low |
|
||||
| SQLI-CFG-006 | [SQLI-CFG-006.sql](SQLI-CFG-006.sql) | Priority boost er slået til | ConfigurationCollector | High |
|
||||
| SQLI-CFG-007 | [SQLI-CFG-007.sql](SQLI-CFG-007.sql) | Lightweight pooling (fiber mode) er slået til | ConfigurationCollector | High |
|
||||
| SQLI-CFG-008 | [SQLI-CFG-008.sql](SQLI-CFG-008.sql) | xp_cmdshell er slået til | ConfigurationCollector | Medium |
|
||||
| SQLI-CFG-009 | [SQLI-CFG-009.sql](SQLI-CFG-009.sql) | Backup-komprimering er ikke standard | ConfigurationCollector, InstanceProbe | Low |
|
||||
| SQLI-CFG-010 | [SQLI-CFG-010.sql](SQLI-CFG-010.sql) | Dedicated Admin Connection kan kun bruges lokalt | ConfigurationCollector | Low |
|
||||
| SQLI-CFG-011 | [SQLI-CFG-011.sql](SQLI-CFG-011.sql) | Konfigurationsændringer venter på RECONFIGURE eller genstart | ConfigurationCollector | Low |
|
||||
| SQLI-CFG-012 | [SQLI-CFG-012.sql](SQLI-CFG-012.sql) | Deadlocks bliver ikke registreret | TraceFlagCollector, InstanceProbe | Low |
|
||||
| SQLI-CFG-013 | [SQLI-CFG-013.sql](SQLI-CFG-013.sql) | Konfiguration ændret | InstanceConfigurationCollector | Info |
|
||||
| SQLI-CPU-001 | [SQLI-CPU-001.sql](SQLI-CPU-001.sql) | Vedvarende højt CPU-forbrug | CpuCollector | SQL Server: Medium fra 75 %, High fra 90 %. Andre processer: Medium. |
|
||||
| SQLI-CPU-002 | [SQLI-CPU-002.sql](SQLI-CPU-002.sql) | Sætning kører næsten uafbrudt | QueryStatsCollector | Medium |
|
||||
| SQLI-DB-001 | [SQLI-DB-001.sql](SQLI-DB-001.sql) | Database er ikke tilgængelig | DatabaseCollector | Critical for SUSPECT, RECOVERY_PENDING og EMERGENCY; Low for OFFLINE. |
|
||||
| SQLI-DB-002 | [SQLI-DB-002.sql](SQLI-DB-002.sql) | AUTO_SHRINK er slået til | DatabaseCollector | High |
|
||||
| SQLI-DB-003 | [SQLI-DB-003.sql](SQLI-DB-003.sql) | AUTO_CLOSE er slået til | DatabaseCollector | Medium |
|
||||
| SQLI-DB-004 | [SQLI-DB-004.sql](SQLI-DB-004.sql) | Sidekontrol er ikke CHECKSUM | DatabaseCollector | Medium |
|
||||
| SQLI-DB-005 | [SQLI-DB-005.sql](SQLI-DB-005.sql) | TRUSTWORTHY er slået til | DatabaseCollector | Medium |
|
||||
| SQLI-DB-006 | [SQLI-DB-006.sql](SQLI-DB-006.sql) | Database kører med et ældre compatibility level | DatabaseCollector, InstanceProbe | Low |
|
||||
| SQLI-DB-007 | [SQLI-DB-007.sql](SQLI-DB-007.sql) | Database mangler en nylig fuld backup | DatabaseCollector | Critical hvis aldrig backet op; High hvis ældre end 7 dage; Medium hvis databasen er i en availability group (backup kan være taget på en anden replika). |
|
||||
| SQLI-DB-008 | [SQLI-DB-008.sql](SQLI-DB-008.sql) | Database i FULL recovery uden log-backups | DatabaseCollector | High; Medium hvis databasen er i en availability group. |
|
||||
| SQLI-DB-009 | [SQLI-DB-009.sql](SQLI-DB-009.sql) | DBCC CHECKDB er ikke kørt for nylig | DatabaseCollector | High hvis aldrig kørt eller ældre end 30 dage; ellers Medium. |
|
||||
| SQLI-DB-010 | [SQLI-DB-010.sql](SQLI-DB-010.sql) | Korrupte sider registreret i suspect_pages | SuspectPageCollector | Critical |
|
||||
| SQLI-DB-011 | [SQLI-DB-011.sql](SQLI-DB-011.sql) | Transaktionsloggen har for mange VLF'er | DatabaseCollector | Medium; High over 10.000 VLF'er. |
|
||||
| SQLI-DB-012 | [SQLI-DB-012.sql](SQLI-DB-012.sql) | Uhensigtsmæssig autogrowth | DatabaseCollector | Low |
|
||||
| SQLI-DB-013 | [SQLI-DB-013.sql](SQLI-DB-013.sql) | Databasefil nærmer sig sin maksimale størrelse | DatabaseCollector | High fra 90 %; Critical når filen har nået MAXSIZE. |
|
||||
| SQLI-DB-014 | [SQLI-DB-014.sql](SQLI-DB-014.sql) | Query Store indsamler ikke længere data | DatabaseCollector | High ved ERROR; ellers Medium. |
|
||||
| SQLI-DB-015 | [SQLI-DB-015.sql](SQLI-DB-015.sql) | tempdb har for få eller ulige store datafiler | DatabaseCollector, ServerCollector | Medium for for få filer; Low for ulige store filer. |
|
||||
| SQLI-DLK-001 | [SQLI-DLK-001.sql](SQLI-DLK-001.sql) | Deadlocks | DeadlockCollector | Medium; High fra 10 deadlocks siden sidste måling. |
|
||||
| SQLI-IDX-001 | [SQLI-IDX-001.sql](SQLI-IDX-001.sql) | Manglende index med stor effekt | IndexCollector | Medium hvis forbedringsmålet er mindst 1.000.000; ellers Low. |
|
||||
| SQLI-IDX-002 | [SQLI-IDX-002.sql](SQLI-IDX-002.sql) | Ubrugt index koster ved hver skrivning | IndexCollector | Low; Medium fra 1 GB. |
|
||||
| SQLI-IDX-003 | [SQLI-IDX-003.sql](SQLI-IDX-003.sql) | Duplikeret eller overlappende index | IndexCollector | Medium for nøjagtige dubletter; Low for overlappende. |
|
||||
| SQLI-IDX-004 | [SQLI-IDX-004.sql](SQLI-IDX-004.sql) | Heap med mange forwarded records | IndexCollector | Medium |
|
||||
| SQLI-IO-001 | [SQLI-IO-001.sql](SQLI-IO-001.sql) | Høj læselatens på drev med datafiler | FileIoCollector | Medium; High fra 50 ms. |
|
||||
| SQLI-IO-002 | [SQLI-IO-002.sql](SQLI-IO-002.sql) | Høj skrivelatens på drev med logfiler | FileIoCollector | Medium; High fra 15 ms. |
|
||||
| SQLI-JOB-001 | [SQLI-JOB-001.sql](SQLI-JOB-001.sql) | SQL Agent-job fejler | AgentJobCollector | High hvis jobnavnet indeholder backup, checkdb, integrity eller dbcc; ellers Medium. |
|
||||
| SQLI-JOB-002 | [SQLI-JOB-002.sql](SQLI-JOB-002.sql) | SQL Server Agent kører ikke | AgentJobCollector, InstanceProbe | High når der er aktive jobs; ellers Low. |
|
||||
| SQLI-LOG-001 | [SQLI-LOG-001.sql](SQLI-LOG-001.sql) | SQL Server har læst beskadigede sider (fejl 823/824/825) | ErrorLogCollector | Critical for 823/824; High for 825. |
|
||||
| SQLI-LOG-002 | [SQLI-LOG-002.sql](SQLI-LOG-002.sql) | I/O-forespørgsler, der tager over 15 sekunder (fejl 833) | ErrorLogCollector | High |
|
||||
| SQLI-LOG-003 | [SQLI-LOG-003.sql](SQLI-LOG-003.sql) | Alvorlige fejl i SQL Servers fejllog (severity 17 og derover) | ErrorLogCollector | High fra severity 20; ellers Medium. |
|
||||
| SQLI-LOG-004 | [SQLI-LOG-004.sql](SQLI-LOG-004.sql) | Mange mislykkede logins | ErrorLogCollector | Medium |
|
||||
| SQLI-LOG-005 | [SQLI-LOG-005.sql](SQLI-LOG-005.sql) | SQL Server har lavet et stack dump | ErrorLogCollector | High |
|
||||
| SQLI-LOG-006 | [SQLI-LOG-006.sql](SQLI-LOG-006.sql) | Fejl i Always On availability groups | ErrorLogCollector | High |
|
||||
| SQLI-MEM-001 | [SQLI-MEM-001.sql](SQLI-MEM-001.sql) | Forespørgsler venter på hukommelse | PerformanceCounterCollector, WaitStatsCollector | High |
|
||||
| SQLI-OPS-001 | [SQLI-OPS-001.sql](SQLI-OPS-001.sql) | Backup eller restore kører markant længere end normalt | LongOperationCollector | Medium |
|
||||
| SQLI-PLAN-001 | [SQLI-PLAN-001.sql](SQLI-PLAN-001.sql) | Implicit konvertering forhindrer index seek | PlanAnalysisCollector | Medium |
|
||||
| SQLI-PLAN-002 | [SQLI-PLAN-002.sql](SQLI-PLAN-002.sql) | Join uden join-betingelse (kartesisk produkt) | PlanAnalysisCollector | High |
|
||||
| SQLI-PLAN-003 | [SQLI-PLAN-003.sql](SQLI-PLAN-003.sql) | Skalar funktion kaldes for hver række | PlanAnalysisCollector | Medium |
|
||||
| SQLI-PLAN-004 | [SQLI-PLAN-004.sql](SQLI-PLAN-004.sql) | Sorteringer og hash joins spilder til tempdb | PlanAnalysisCollector | Medium |
|
||||
| SQLI-PLAN-005 | [SQLI-PLAN-005.sql](SQLI-PLAN-005.sql) | Forespørgsel får langt mere hukommelse, end den bruger | PlanAnalysisCollector | Medium |
|
||||
| SQLI-QS-001 | [SQLI-QS-001.sql](SQLI-QS-001.sql) | Planregression: forespørgsel har fået en langsommere plan | QueryStoreCollector | Medium; High når ekstra tid er mindst 10 minutter i døgnet. |
|
||||
| SQLI-QS-002 | [SQLI-QS-002.sql](SQLI-QS-002.sql) | Forceret plan kan ikke bruges | QueryStoreCollector | High |
|
||||
| SQLI-QS-003 | [SQLI-QS-003.sql](SQLI-QS-003.sql) | Parameterfølsom forespørgsel (parameter sniffing) | QueryStoreCollector | Medium |
|
||||
| SQLI-REPL-001 | [SQLI-REPL-001.sql](SQLI-REPL-001.sql) | Replikering fejler | ReplicationCollector | High |
|
||||
| SQLI-REPL-002 | [SQLI-REPL-002.sql](SQLI-REPL-002.sql) | Replikering er forsinket | ReplicationCollector | Medium |
|
||||
| SQLI-REQ-001 | [SQLI-REQ-001.sql](SQLI-REQ-001.sql) | Sætning har kørt længe | ActivityCollector | Medium |
|
||||
| SQLI-SEC-001 | [SQLI-SEC-001.sql](SQLI-SEC-001.sql) | Ny forhøjet rettighed på serveren | PrivilegeCollector | High for sysadmin, securityadmin og CONTROL SERVER; Medium for de øvrige faste serverroller. |
|
||||
| SQLI-SEC-002 | [SQLI-SEC-002.sql](SQLI-SEC-002.sql) | For mange personer og konti med sysadmin | PrivilegeCollector | Medium |
|
||||
| SQLI-STAT-001 | [SQLI-STAT-001.sql](SQLI-STAT-001.sql) | Forældede statistikker på store tabeller | IndexCollector | Low |
|
||||
| SQLI-STAT-002 | [SQLI-STAT-002.sql](SQLI-STAT-002.sql) | Automatisk statistik er slået fra | DatabaseCollector | Medium |
|
||||
| SQLI-SVC-001 | [SQLI-SVC-001.sql](SQLI-SVC-001.sql) | En SQL Server-tjeneste, der skal starte automatisk, kører ikke | InstanceConfigurationCollector | High |
|
||||
| SQLI-TEMP-001 | [SQLI-TEMP-001.sql](SQLI-TEMP-001.sql) | Version store i tempdb er stor eller vokser | TempdbCollector | Medium |
|
||||
| SQLI-TEMP-002 | [SQLI-TEMP-002.sql](SQLI-TEMP-002.sql) | tempdb er næsten fuld | TempdbCollector | High |
|
||||
| SQLI-TEMP-003 | [SQLI-TEMP-003.sql](SQLI-TEMP-003.sql) | Session bruger meget tempdb i lang tid | TempdbCollector | Medium |
|
||||
| SQLI-TRAN-001 | [SQLI-TRAN-001.sql](SQLI-TRAN-001.sql) | Transaktion har været åben længe | ActivityCollector | Medium; High når den har været åben 6 x grænsen. |
|
||||
| SQLI-TRAN-002 | [SQLI-TRAN-002.sql](SQLI-TRAN-002.sql) | Transaktion bruger meget transaktionslog | ActivityCollector | Medium |
|
||||
| SQLI-VER-001 | [SQLI-VER-001.sql](SQLI-VER-001.sql) | SQL Server-versionens supportstatus | InstanceProbe | Critical når extended support er udløbet; High når mainstream er udløbet og der er højst 365 dage til extended support slutter; ellers Medium i extended support. |
|
||||
| SQLI-VER-002 | [SQLI-VER-002.sql](SQLI-VER-002.sql) | Instansen mangler opdateringer | InstanceProbe | High når versionen stadig er i support; Medium når den er ude af support (så er SQLI-VER-001 det vigtigste fund). |
|
||||
| SQLI-WAIT-001 | [SQLI-WAIT-001.sql](SQLI-WAIT-001.sql) | SQL Server løber tør for worker threads | WaitStatsCollector | Critical |
|
||||
| SQLI-WAIT-002 | [SQLI-WAIT-002.sql](SQLI-WAIT-002.sql) | Tasks venter på CPU (høj signal wait) | WaitStatsCollector | Medium; High fra 40 %. |
|
||||
| SQLI-WAIT-003 | [SQLI-WAIT-003.sql](SQLI-WAIT-003.sql) | Sessioner venter meget på låse | WaitStatsCollector | Medium; High fra 5 ventende tasks i gennemsnit. |
|
||||
| SQLI-WAIT-004 | [SQLI-WAIT-004.sql](SQLI-WAIT-004.sql) | Forespørgsler venter meget på at læse data fra disk | WaitStatsCollector | Medium; High fra 8 ventende tasks i gennemsnit. |
|
||||
| SQLI-WAIT-005 | [SQLI-WAIT-005.sql](SQLI-WAIT-005.sql) | Commits venter på langsom skrivning til transaktionsloggen | WaitStatsCollector | Medium; High fra 15 ms i gennemsnit. |
|
||||
| SQLI-WAIT-006 | [SQLI-WAIT-006.sql](SQLI-WAIT-006.sql) | Parallelle forespørgsler venter meget på hinanden | WaitStatsCollector | Medium; High fra 16 ventende tasks i gennemsnit. |
|
||||
| SQLI-WAIT-007 | [SQLI-WAIT-007.sql](SQLI-WAIT-007.sql) | Contention på sider i hukommelsen (PAGELATCH) | WaitStatsCollector | Medium; High fra 4 ventende tasks i gennemsnit. |
|
||||
| COM-AX-001 | [COM-AX-001.sql](COM-AX-001.sql) | Dynamics AX 3.0 er uden support fra Microsoft | CustomQueryCollector | Medium |
|
||||
| COM-AX-002 | [COM-AX-002.sql](COM-AX-002.sql) | Dynamics AX 3.0 kører på en SQL Server-version, der ikke var understøttet til AX 3.0 | CustomQueryCollector | Medium |
|
||||
| COM-AX-003 | [COM-AX-003.sql](COM-AX-003.sql) | Dynamics AX-database på en instans, hvor MAXDOP ikke er 1 (SQL Server 2005-2014) | CustomQueryCollector | Medium |
|
||||
| COM-AX-004 | [COM-AX-004.sql](COM-AX-004.sql) | Dynamics AX-database, hvor MAXDOP ikke er 1 (SQL Server 2016 og nyere) | CustomQueryCollector | Medium |
|
||||
| COM-AX-005 | [COM-AX-005.sql](COM-AX-005.sql) | Dynamics AX-tabeller uden unikt RecId-indeks | CustomQueryCollector | Medium |
|
||||
| COM-AX-006 | [COM-AX-006.sql](COM-AX-006.sql) | Store Dynamics AX-tabeller uden clustered index (heaps) | CustomQueryCollector | Medium |
|
||||
| COM-AX-007 | [COM-AX-007.sql](COM-AX-007.sql) | Automatiske statistikker er slået fra i en Dynamics AX-database | CustomQueryCollector | High |
|
||||
| COM-CFG-001 | [COM-CFG-001.sql](COM-CFG-001.sql) | Default trace er slået fra | CustomQueryCollector | Low |
|
||||
| COM-DB-001 | [COM-DB-001.sql](COM-DB-001.sql) | Fremmednøgler, som SQL Server ikke stoler på | CustomQueryCollector | Low |
|
||||
| COM-FT-001 | [COM-FT-001.sql](COM-FT-001.sql) | Fulltext-katalog er sat på pause, fordi disken er fuld | CustomQueryCollector | High |
|
||||
| COM-FT-002 | [COM-FT-002.sql](COM-FT-002.sql) | Fulltext-katalog er sat på pause eller drosles | CustomQueryCollector | Medium |
|
||||
| COM-FT-003 | [COM-FT-003.sql](COM-FT-003.sql) | Fulltext-indeks uden automatisk opdatering er ikke opdateret i over en uge | CustomQueryCollector | Low |
|
||||
| COM-FT-004 | [COM-FT-004.sql](COM-FT-004.sql) | Fulltext-indeks uden automatisk opdatering er ikke opdateret i over 30 dage | CustomQueryCollector | Medium |
|
||||
| COM-FT-005 | [COM-FT-005.sql](COM-FT-005.sql) | Fulltext-indeks er deaktiveret | CustomQueryCollector | Medium |
|
||||
| COM-SEC-001 | [COM-SEC-001.sql](COM-SEC-001.sql) | Login'et sa er aktivt | CustomQueryCollector | Medium |
|
||||
| COM-SEC-002 | [COM-SEC-002.sql](COM-SEC-002.sql) | Database ejes af et login, der ikke findes | CustomQueryCollector | Low |
|
||||
|
||||
## Collectors
|
||||
|
||||
| Collector | Fil | Interval | Versioner | Bruges af |
|
||||
|---|---|---|---|---|
|
||||
| [InstanceProbe](_collectors/InstanceProbe.sql) | `src/SQLInsight.Connectivity/InstanceProbe.cs` | én gang, når agenten forbinder til instansen | Alle (SQL Server 2000 og nyere) | 6 regler |
|
||||
| [ServerCollector](_collectors/ServerCollector.sql) | `src/SQLInsight.Collectors/Instance/ServerCollector.cs` | 15 min som standard (SQLInsight:CollectorIntervals:server) | Alle (SQL Server 2000 og nyere) | 5 regler |
|
||||
| [ConfigurationCollector](_collectors/ConfigurationCollector.sql) | `src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs` | 15 min som standard (SQLInsight:CollectorIntervals:configuration) | Alle (SQL Server 2000 og nyere) | 11 regler |
|
||||
| [TraceFlagCollector](_collectors/TraceFlagCollector.sql) | `src/SQLInsight.Collectors/Instance/TraceFlagCollector.cs` | 15 min som standard (SQLInsight:CollectorIntervals:trace-flags) | Alle (SQL Server 2000 og nyere) | 1 regel |
|
||||
| [InstanceConfigurationCollector](_collectors/InstanceConfigurationCollector.sql) | `src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs` | 15 min som standard (SQLInsight:CollectorIntervals:instance-config) | Alle; tjenester og IFI fra SQL Server 2008 R2 SP1 | 2 regler |
|
||||
| [PrivilegeCollector](_collectors/PrivilegeCollector.sql) | `src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs` | 15 min som standard (SQLInsight:CollectorIntervals:privileges) | SQL Server 2005 og nyere | 2 regler |
|
||||
| [DatabaseCollector](_collectors/DatabaseCollector.sql) | `src/SQLInsight.Collectors/Databases/DatabaseCollector.cs` | 15 min som standard (SQLInsight:CollectorIntervals:databases) | Alle (SQL Server 2000 og nyere); CHECKDB og VLF'er fra 2016 SP2; Query Store fra 2016 | 15 regler |
|
||||
| [SuspectPageCollector](_collectors/SuspectPageCollector.sql) | `src/SQLInsight.Collectors/Instance/SuspectPageCollector.cs` | 15 min som standard (SQLInsight:CollectorIntervals:suspect-pages) | SQL Server 2005 og nyere | 1 regel |
|
||||
| [PlanCacheCollector](_collectors/PlanCacheCollector.sql) | `src/SQLInsight.Collectors/Instance/PlanCacheCollector.cs` | 15 min som standard (SQLInsight:CollectorIntervals:plan-cache) | SQL Server 2005 og nyere | 1 regel |
|
||||
| [WaitStatsCollector](_collectors/WaitStatsCollector.sql) | `src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs` | 5 min som standard (SQLInsight:CollectorIntervals:wait-stats) | Alle (SQL Server 2000 og nyere) | 8 regler |
|
||||
| [FileIoCollector](_collectors/FileIoCollector.sql) | `src/SQLInsight.Collectors/Performance/FileIoCollector.cs` | 5 min som standard (SQLInsight:CollectorIntervals:file-io) | SQL Server 2005 og nyere; drev fra 2008 R2 SP1 | 2 regler |
|
||||
| [QueryStatsCollector](_collectors/QueryStatsCollector.sql) | `src/SQLInsight.Collectors/Performance/QueryStatsCollector.cs` | 5 min som standard (SQLInsight:CollectorIntervals:query-stats) | SQL Server 2005 og nyere | 1 regel |
|
||||
| [WaitSamplingCollector](_collectors/WaitSamplingCollector.sql) | `src/SQLInsight.Collectors/Performance/WaitSamplingCollector.cs` | 15 sek som standard (SQLInsight:CollectorIntervals:wait-sampling) | SQL Server 2005 og nyere | ingen regel |
|
||||
| [LongOperationCollector](_collectors/LongOperationCollector.sql) | `src/SQLInsight.Collectors/Instance/LongOperationCollector.cs` | 1 min som standard (SQLInsight:CollectorIntervals:long-operations) | SQL Server 2005 og nyere | 1 regel |
|
||||
| [ErrorLogCollector](_collectors/ErrorLogCollector.sql) | `src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs` | 5 min som standard (SQLInsight:CollectorIntervals:error-log) | SQL Server 2005 og nyere | 6 regler |
|
||||
| [TempdbCollector](_collectors/TempdbCollector.sql) | `src/SQLInsight.Collectors/Instance/TempdbCollector.cs` | 5 min som standard (SQLInsight:CollectorIntervals:tempdb) | SQL Server 2005 og nyere | 3 regler |
|
||||
| [ReplicationCollector](_collectors/ReplicationCollector.sql) | `src/SQLInsight.Collectors/Instance/ReplicationCollector.cs` | 15 min som standard (SQLInsight:CollectorIntervals:replication) | SQL Server 2005 og nyere | 2 regler |
|
||||
| [PerformanceCounterCollector](_collectors/PerformanceCounterCollector.sql) | `src/SQLInsight.Collectors/Performance/PerformanceCounterCollector.cs` | 5 min som standard (SQLInsight:CollectorIntervals:performance-counters) | Alle (SQL Server 2000 og nyere) | 2 regler |
|
||||
| [CpuCollector](_collectors/CpuCollector.sql) | `src/SQLInsight.Collectors/Performance/CpuCollector.cs` | 5 min som standard (SQLInsight:CollectorIntervals:cpu) | SQL Server 2005 og nyere | 2 regler |
|
||||
| [BlockingCollector](_collectors/BlockingCollector.sql) | `src/SQLInsight.Collectors/Concurrency/BlockingCollector.cs` | 1 min som standard (SQLInsight:CollectorIntervals:blocking) | Alle (SQL Server 2000 og nyere) | 1 regel |
|
||||
| [ActivityCollector](_collectors/ActivityCollector.sql) | `src/SQLInsight.Collectors/Concurrency/ActivityCollector.cs` | 1 min som standard (SQLInsight:CollectorIntervals:activity) | SQL Server 2005 og nyere | 3 regler |
|
||||
| [DeadlockCollector](_collectors/DeadlockCollector.sql) | `src/SQLInsight.Collectors/Concurrency/DeadlockCollector.cs` | 5 min som standard (SQLInsight:CollectorIntervals:deadlocks) | SQL Server 2008 og nyere (filer fra 2012, ellers ring buffer) | 1 regel |
|
||||
| [QueryStoreCollector](_collectors/QueryStoreCollector.sql) | `src/SQLInsight.Collectors/Performance/QueryStoreCollector.cs` | 30 min som standard (SQLInsight:CollectorIntervals:query-store) | SQL Server 2016 og nyere | 3 regler |
|
||||
| [PlanAnalysisCollector](_collectors/PlanAnalysisCollector.sql) | `src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs` | 30 min som standard (SQLInsight:CollectorIntervals:plan-analysis) | SQL Server 2005 SP2 og nyere | 5 regler |
|
||||
| [IndexCollector](_collectors/IndexCollector.sql) | `src/SQLInsight.Collectors/Databases/IndexCollector.cs` | 6 timer som standard (SQLInsight:CollectorIntervals:indexes) | SQL Server 2005 og nyere | 5 regler |
|
||||
| [AvailabilityGroupCollector](_collectors/AvailabilityGroupCollector.sql) | `src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs` | 1 min som standard (SQLInsight:CollectorIntervals:availability-groups) | SQL Server 2012 og nyere med Always On slået til | 3 regler |
|
||||
| [AgentJobCollector](_collectors/AgentJobCollector.sql) | `src/SQLInsight.Collectors/Instance/AgentJobCollector.cs` | 5 min som standard (SQLInsight:CollectorIntervals:agent-jobs) | SQL Server 2005 og nyere | 2 regler |
|
||||
| [CustomQueryCollector](_collectors/CustomQueryCollector.sql) | `src/SQLInsight.Collectors/Custom/CustomQueryCollector.cs` | 15 min som standard (SQLInsight:CollectorIntervals:custom-rules) | SQL Server 2005 og nyere (pr. regel: minimumVersion) | 16 regler |
|
||||
85
SQL Scripts/SQLI-AG-001.sql
Normal file
85
SQL Scripts/SQLI-AG-001.sql
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AG-001: Always On availability group er ikke sund
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AG-001
|
||||
-- Titel: Always On availability group er ikke sund
|
||||
-- Alvor: High for DISCONNECTED, NOT_HEALTHY og suspenderet; Medium for PARTIALLY_HEALTHY.
|
||||
-- Versioner: SQL Server 2012 og nyere med Always On slået til (IsHadrEnabled).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om replikaer eller databaser i en availability group ikke er sunde: afbrudt, ikke synkroniseret eller
|
||||
-- suspenderet.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund pr. replika med connected_state_desc = DISCONNECTED eller synchronization_health_desc
|
||||
-- NOT_HEALTHY/PARTIALLY_HEALTHY, og pr. database-replika, der er suspenderet eller har synchronization_health_desc
|
||||
-- NOT_HEALTHY/PARTIALLY_HEALTHY.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AvailabilityGroupCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs
|
||||
-- Medlemmer: AvailabilityGroupCollector.ReplicasSql, AvailabilityGroupCollector.DatabasesSql,
|
||||
-- AvailabilityGroupCollector.ClusterMembersSql
|
||||
-- Interval: 1 min som standard (SQLInsight:CollectorIntervals:availability-groups)
|
||||
-- Delt script: SQL Scripts/_collectors/AvailabilityGroupCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Availability/AvailabilityRules.cs : AvailabilityGroupHealthRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AvailabilityGroupCollector: Always On: replikaer, databasereplikaer (køer, hastigheder, commit-tid) og
|
||||
-- Windows-clusterets medlemmer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere med Always On slået til
|
||||
-- Kilde: AvailabilityGroupCollector.ReplicasSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs : AvailabilityGroupCollector.ReplicasSql
|
||||
SELECT ag.name, ar.replica_server_name, ars.is_local, ars.role_desc, ars.connected_state_desc, ars.synchronization_health_desc,
|
||||
ar.availability_mode_desc, ar.failover_mode_desc
|
||||
FROM sys.availability_groups ag
|
||||
JOIN sys.availability_replicas ar ON ar.group_id = ag.group_id
|
||||
LEFT JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = ar.replica_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere med Always On slået til
|
||||
-- Kilde: AvailabilityGroupCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs : AvailabilityGroupCollector.DatabasesSql
|
||||
SELECT ag.name, DB_NAME(drs.database_id), ar.replica_server_name, drs.is_local,
|
||||
CASE WHEN ars.role = 1 THEN 1 ELSE 0 END,
|
||||
drs.synchronization_state_desc, drs.synchronization_health_desc, drs.is_suspended, drs.suspend_reason_desc,
|
||||
drs.log_send_queue_size, drs.log_send_rate, drs.redo_queue_size, drs.redo_rate, drs.last_commit_time
|
||||
FROM sys.dm_hadr_database_replica_states drs
|
||||
JOIN sys.availability_replicas ar ON ar.replica_id = drs.replica_id
|
||||
JOIN sys.availability_groups ag ON ag.group_id = drs.group_id
|
||||
LEFT JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = drs.replica_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere med Always On slået til (tom uden Windows-cluster)
|
||||
-- Kilde: AvailabilityGroupCollector.ClusterMembersSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs : AvailabilityGroupCollector.ClusterMembersSql
|
||||
SELECT member_name, member_type_desc, member_state, member_state_desc, number_of_quorum_votes FROM sys.dm_hadr_cluster_members
|
||||
GO
|
||||
84
SQL Scripts/SQLI-AG-002.sql
Normal file
84
SQL Scripts/SQLI-AG-002.sql
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AG-002: Sekundær replika er langt bagud
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AG-002
|
||||
-- Titel: Sekundær replika er langt bagud
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2012 og nyere med Always On slået til.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en sekundær replika er langt bagud: muligt datatab (commit-forsinkelse) eller lang failover-tid (redo queue).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For hver sekundær, ikke suspenderet database-replika: muligt datatab = last_commit_time på den primære - på den
|
||||
-- sekundære (sekunder); recovery-tid = redo_queue_size / redo_rate (sekunder). Fund hvis datatab >= 60 s eller
|
||||
-- recovery-tid >= 600 s.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 60 sekunder (MaxDataLossSeconds) og 600 sekunder (MaxRecoverySeconds), fast i koden.
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AvailabilityGroupCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs
|
||||
-- Medlemmer: AvailabilityGroupCollector.ReplicasSql, AvailabilityGroupCollector.DatabasesSql,
|
||||
-- AvailabilityGroupCollector.ClusterMembersSql
|
||||
-- Interval: 1 min som standard (SQLInsight:CollectorIntervals:availability-groups)
|
||||
-- Delt script: SQL Scripts/_collectors/AvailabilityGroupCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Availability/AvailabilityRules.cs : AvailabilityGroupLagRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AvailabilityGroupCollector: Always On: replikaer, databasereplikaer (køer, hastigheder, commit-tid) og
|
||||
-- Windows-clusterets medlemmer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere med Always On slået til
|
||||
-- Kilde: AvailabilityGroupCollector.ReplicasSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs : AvailabilityGroupCollector.ReplicasSql
|
||||
SELECT ag.name, ar.replica_server_name, ars.is_local, ars.role_desc, ars.connected_state_desc, ars.synchronization_health_desc,
|
||||
ar.availability_mode_desc, ar.failover_mode_desc
|
||||
FROM sys.availability_groups ag
|
||||
JOIN sys.availability_replicas ar ON ar.group_id = ag.group_id
|
||||
LEFT JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = ar.replica_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere med Always On slået til
|
||||
-- Kilde: AvailabilityGroupCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs : AvailabilityGroupCollector.DatabasesSql
|
||||
SELECT ag.name, DB_NAME(drs.database_id), ar.replica_server_name, drs.is_local,
|
||||
CASE WHEN ars.role = 1 THEN 1 ELSE 0 END,
|
||||
drs.synchronization_state_desc, drs.synchronization_health_desc, drs.is_suspended, drs.suspend_reason_desc,
|
||||
drs.log_send_queue_size, drs.log_send_rate, drs.redo_queue_size, drs.redo_rate, drs.last_commit_time
|
||||
FROM sys.dm_hadr_database_replica_states drs
|
||||
JOIN sys.availability_replicas ar ON ar.replica_id = drs.replica_id
|
||||
JOIN sys.availability_groups ag ON ag.group_id = drs.group_id
|
||||
LEFT JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = drs.replica_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere med Always On slået til (tom uden Windows-cluster)
|
||||
-- Kilde: AvailabilityGroupCollector.ClusterMembersSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs : AvailabilityGroupCollector.ClusterMembersSql
|
||||
SELECT member_name, member_type_desc, member_state, member_state_desc, number_of_quorum_votes FROM sys.dm_hadr_cluster_members
|
||||
GO
|
||||
83
SQL Scripts/SQLI-AG-003.sql
Normal file
83
SQL Scripts/SQLI-AG-003.sql
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AG-003: En node eller et vidne i clusteret er nede
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AG-003
|
||||
-- Titel: En node eller et vidne i clusteret er nede
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2012 og nyere med Always On og et Windows Server Failover Cluster (tom ved CLUSTER_TYPE
|
||||
-- NONE/EXTERNAL).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en node eller et vidne i Windows-clusteret under availability groups er nede, så et tab mere kan tage quorum.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund pr. medlem af sys.dm_hadr_cluster_members med member_state <> 1 (UP).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AvailabilityGroupCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs
|
||||
-- Medlemmer: AvailabilityGroupCollector.ReplicasSql, AvailabilityGroupCollector.DatabasesSql,
|
||||
-- AvailabilityGroupCollector.ClusterMembersSql
|
||||
-- Interval: 1 min som standard (SQLInsight:CollectorIntervals:availability-groups)
|
||||
-- Delt script: SQL Scripts/_collectors/AvailabilityGroupCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Availability/AvailabilityRules.cs : ClusterMemberDownRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AvailabilityGroupCollector: Always On: replikaer, databasereplikaer (køer, hastigheder, commit-tid) og
|
||||
-- Windows-clusterets medlemmer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere med Always On slået til
|
||||
-- Kilde: AvailabilityGroupCollector.ReplicasSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs : AvailabilityGroupCollector.ReplicasSql
|
||||
SELECT ag.name, ar.replica_server_name, ars.is_local, ars.role_desc, ars.connected_state_desc, ars.synchronization_health_desc,
|
||||
ar.availability_mode_desc, ar.failover_mode_desc
|
||||
FROM sys.availability_groups ag
|
||||
JOIN sys.availability_replicas ar ON ar.group_id = ag.group_id
|
||||
LEFT JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = ar.replica_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere med Always On slået til
|
||||
-- Kilde: AvailabilityGroupCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs : AvailabilityGroupCollector.DatabasesSql
|
||||
SELECT ag.name, DB_NAME(drs.database_id), ar.replica_server_name, drs.is_local,
|
||||
CASE WHEN ars.role = 1 THEN 1 ELSE 0 END,
|
||||
drs.synchronization_state_desc, drs.synchronization_health_desc, drs.is_suspended, drs.suspend_reason_desc,
|
||||
drs.log_send_queue_size, drs.log_send_rate, drs.redo_queue_size, drs.redo_rate, drs.last_commit_time
|
||||
FROM sys.dm_hadr_database_replica_states drs
|
||||
JOIN sys.availability_replicas ar ON ar.replica_id = drs.replica_id
|
||||
JOIN sys.availability_groups ag ON ag.group_id = drs.group_id
|
||||
LEFT JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = drs.replica_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere med Always On slået til (tom uden Windows-cluster)
|
||||
-- Kilde: AvailabilityGroupCollector.ClusterMembersSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AvailabilityGroupCollector.cs : AvailabilityGroupCollector.ClusterMembersSql
|
||||
SELECT member_name, member_type_desc, member_state, member_state_desc, number_of_quorum_votes FROM sys.dm_hadr_cluster_members
|
||||
GO
|
||||
130
SQL Scripts/SQLI-ANOM-001.sql
Normal file
130
SQL Scripts/SQLI-ANOM-001.sql
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-ANOM-001: Usædvanlig belastning i forhold til det normale
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-ANOM-001
|
||||
-- Titel: Usædvanlig belastning i forhold til det normale
|
||||
-- Alvor: CPU: Medium. Batch requests: Low ved stigning, Medium ved fald. Page life expectancy: Medium.
|
||||
-- Versioner: SQL Server 2005 og nyere (CPU); tællerne fra 2000.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om belastningen er usædvanlig i forhold til, hvad der er normalt for netop denne time på ugen.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Baseline beregnes af agenten i C# fra dens EGET repository (timegennemsnit de seneste 28 dage for samme time på
|
||||
-- ugen +/- 1 time, mindst 6 målepunkter) - ikke fra den overvågede server. CPU: gns. af de seneste 15 minutters
|
||||
-- ProcessUtilization >= 50 % og >= middel + max(3 x std.afv., 20). Batch requests/s (forskel mellem to
|
||||
-- tællermålinger): >= 100 og >= middel + max(3 x std.afv., middel) giver stigning; middel >= 50 og nu <= 30 % af
|
||||
-- middel giver fald. Page life expectancy: middel >= 300 s og nu <= 30 % af middel.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Fast i koden (AnomalyRule og BaselineCalculator.MinSamples = 6).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CpuCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/CpuCollector.cs
|
||||
-- Medlemmer: CpuCollector.Sql, CpuCollector.HostPlatformSql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:cpu)
|
||||
-- Delt script: SQL Scripts/_collectors/CpuCollector.sql
|
||||
-- PerformanceCounterCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/PerformanceCounterCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), PerformanceCounterCollector.BuildSql(dmv: true),
|
||||
-- PerformanceCounterCollector.BuildSql(dmv: false)
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:performance-counters)
|
||||
-- Delt script: SQL Scripts/_collectors/PerformanceCounterCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/AnomalyRule.cs : AnomalyRule.Evaluate
|
||||
--
|
||||
-- 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 (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CpuCollector: SQL Servers og systemets CPU-forbrug pr. minut (scheduler monitor ring buffer, op til 60 minutter).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CpuCollector.Sql
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/CpuCollector.cs : CpuCollector.Sql
|
||||
DECLARE @now_ticks bigint;
|
||||
SELECT @now_ticks = ms_ticks FROM sys.dm_os_sys_info;
|
||||
SELECT TOP (60)
|
||||
DATEADD(second, CAST((rb.[timestamp] - @now_ticks) / 1000 AS int), GETUTCDATE()),
|
||||
rb.record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]', 'int'),
|
||||
rb.record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int')
|
||||
FROM (
|
||||
SELECT [timestamp], CONVERT(xml, record) AS record
|
||||
FROM sys.dm_os_ring_buffers
|
||||
WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR' AND record LIKE N'%<SystemHealth>%'
|
||||
) rb
|
||||
ORDER BY rb.[timestamp] DESC
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2017 og nyere (Windows eller Linux)
|
||||
-- Kilde: CpuCollector.HostPlatformSql
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/CpuCollector.cs : CpuCollector.HostPlatformSql
|
||||
SELECT host_platform FROM sys.dm_os_host_info
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- PerformanceCounterCollector: Udvalgte performance counters: memory grants, page life expectancy, forbindelser,
|
||||
-- blokerede processer, batch requests og kompileringer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt
|
||||
-- Kilde: PerformanceCounterCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: PerformanceCounterCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: PerformanceCounterCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: PerformanceCounterCollector.BuildSql(dmv)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PerformanceCounterCollector.cs : PerformanceCounterCollector.BuildSql(dmv: true)
|
||||
SELECT RTRIM(object_name), RTRIM(counter_name), CAST(cntr_value AS bigint)
|
||||
FROM sys.dm_os_performance_counters
|
||||
WHERE (object_name LIKE N'%Memory Manager%' AND counter_name IN (N'Memory Grants Pending', N'Memory Grants Outstanding'))
|
||||
OR (object_name LIKE N'%Buffer Manager%' AND counter_name = N'Page life expectancy')
|
||||
OR (object_name LIKE N'%General Statistics%' AND counter_name IN (N'User Connections', N'Processes blocked'))
|
||||
OR (object_name LIKE N'%SQL Statistics%' AND counter_name IN (N'Batch Requests/sec', N'SQL Compilations/sec', N'SQL Re-Compilations/sec'))
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: PerformanceCounterCollector.BuildSql(sysperfinfo)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PerformanceCounterCollector.cs : PerformanceCounterCollector.BuildSql(dmv: false)
|
||||
SELECT RTRIM(object_name), RTRIM(counter_name), CAST(cntr_value AS bigint)
|
||||
FROM master.dbo.sysperfinfo
|
||||
WHERE (object_name LIKE N'%Memory Manager%' AND counter_name IN (N'Memory Grants Pending', N'Memory Grants Outstanding'))
|
||||
OR (object_name LIKE N'%Buffer Manager%' AND counter_name = N'Page life expectancy')
|
||||
OR (object_name LIKE N'%General Statistics%' AND counter_name IN (N'User Connections', N'Processes blocked'))
|
||||
OR (object_name LIKE N'%SQL Statistics%' AND counter_name IN (N'Batch Requests/sec', N'SQL Compilations/sec', N'SQL Re-Compilations/sec'))
|
||||
GO
|
||||
102
SQL Scripts/SQLI-BLK-001.sql
Normal file
102
SQL Scripts/SQLI-BLK-001.sql
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-BLK-001: Langvarig blocking
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-BLK-001
|
||||
-- Titel: Langvarig blocking
|
||||
-- Alvor: Medium; High når længste ventetid er mindst 5 minutter eller mindst 10 sessioner er blokeret.
|
||||
-- Versioner: Alle (SQL Server 2000 via master.dbo.sysprocesses).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om der er blocking-kæder, der har varet længe nok til at genere brugerne.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- SQL'en henter alle blokerede sessioner og deres blokerere hvert minut. I C# findes head blockers (blokerer andre,
|
||||
-- er ikke selv blokeret); for hver følges hele kæden. Fund hvis den længst ventende i kæden har ventet mindst 30
|
||||
-- sekunder. En head blocker, der er 'sleeping' med åben transaktion, beskrives særskilt.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 30.000 ms (BlockingRule.MinBlockedMs); High fra 300.000 ms eller 10 blokerede (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- BlockingCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Concurrency/BlockingCollector.cs
|
||||
-- Medlemmer: BlockingCollector.BuildSql2005(version), BlockingCollector.Sql2000
|
||||
-- Interval: 1 min som standard (SQLInsight:CollectorIntervals:blocking)
|
||||
-- Delt script: SQL Scripts/_collectors/BlockingCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Concurrency/ConcurrencyRules.cs : BlockingRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- BlockingCollector: Blokerede sessioner og deres blokerere lige nu, med sætning og åbne transaktioner.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere
|
||||
-- Kilde: BlockingCollector.BuildSql2005(2012+)
|
||||
-- Kode: src/SQLInsight.Collectors/Concurrency/BlockingCollector.cs : BlockingCollector.BuildSql2005(version)
|
||||
SELECT s.session_id, NULLIF(r.blocking_session_id, 0), COALESCE(r.status, s.status), r.wait_type, r.wait_time, r.wait_resource,
|
||||
DB_NAME(COALESCE(r.database_id, s.database_id)), s.login_name, s.host_name, s.program_name, s.open_transaction_count,
|
||||
LEFT(CASE WHEN r.sql_handle IS NOT NULL AND r.statement_start_offset IS NOT NULL
|
||||
THEN SUBSTRING(t.text, r.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN r.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE r.statement_end_offset END
|
||||
- r.statement_start_offset) / 2 + 1)
|
||||
ELSE t.text END, 4000),
|
||||
s.last_request_end_time
|
||||
FROM sys.dm_exec_sessions s
|
||||
LEFT JOIN sys.dm_exec_requests r ON r.session_id = s.session_id
|
||||
LEFT JOIN sys.dm_exec_connections c ON c.session_id = s.session_id
|
||||
OUTER APPLY sys.dm_exec_sql_text(COALESCE(r.sql_handle, c.most_recent_sql_handle)) t
|
||||
WHERE r.blocking_session_id > 0
|
||||
OR s.session_id IN (SELECT blocking_session_id FROM sys.dm_exec_requests WHERE blocking_session_id > 0)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: BlockingCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Concurrency/BlockingCollector.cs : BlockingCollector.BuildSql2005(version)
|
||||
SELECT s.session_id, NULLIF(r.blocking_session_id, 0), COALESCE(r.status, s.status), r.wait_type, r.wait_time, r.wait_resource,
|
||||
DB_NAME(r.database_id), s.login_name, s.host_name, s.program_name, (SELECT COUNT(*) FROM sys.dm_tran_session_transactions st WHERE st.session_id = s.session_id),
|
||||
LEFT(CASE WHEN r.sql_handle IS NOT NULL AND r.statement_start_offset IS NOT NULL
|
||||
THEN SUBSTRING(t.text, r.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN r.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE r.statement_end_offset END
|
||||
- r.statement_start_offset) / 2 + 1)
|
||||
ELSE t.text END, 4000),
|
||||
s.last_request_end_time
|
||||
FROM sys.dm_exec_sessions s
|
||||
LEFT JOIN sys.dm_exec_requests r ON r.session_id = s.session_id
|
||||
LEFT JOIN sys.dm_exec_connections c ON c.session_id = s.session_id
|
||||
OUTER APPLY sys.dm_exec_sql_text(COALESCE(r.sql_handle, c.most_recent_sql_handle)) t
|
||||
WHERE r.blocking_session_id > 0
|
||||
OR s.session_id IN (SELECT blocking_session_id FROM sys.dm_exec_requests WHERE blocking_session_id > 0)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: BlockingCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Concurrency/BlockingCollector.cs : BlockingCollector.Sql2000
|
||||
SELECT p.spid, NULLIF(CASE WHEN p.blocked = p.spid THEN 0 ELSE p.blocked END, 0), RTRIM(p.status), RTRIM(p.lastwaittype),
|
||||
p.waittime, RTRIM(p.waitresource), DB_NAME(p.dbid), RTRIM(p.loginame), RTRIM(p.hostname), RTRIM(p.program_name),
|
||||
p.open_tran, CAST(NULL AS nvarchar(4000)), p.last_batch
|
||||
FROM master.dbo.sysprocesses p
|
||||
WHERE (p.blocked > 0 AND p.blocked <> p.spid)
|
||||
OR p.spid IN (SELECT blocked FROM master.dbo.sysprocesses WHERE blocked > 0 AND blocked <> spid)
|
||||
GO
|
||||
145
SQL Scripts/SQLI-CFG-001.sql
Normal file
145
SQL Scripts/SQLI-CFG-001.sql
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-001: max server memory er ikke sat
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-001
|
||||
-- Titel: max server memory er ikke sat
|
||||
-- Alvor: High
|
||||
-- Versioner: Alle (SQL Server 2000 og nyere). Ikke relevant på Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om 'max server memory (MB)' står på standardværdien, så SQL Server kan tage al hukommelse og presse Windows til
|
||||
-- paging.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis value_in_use for 'max server memory (MB)' (ConfigurationCollector) er >= 2147483647. Den anbefalede
|
||||
-- værdi i fundet beregnes af fysisk hukommelse (ServerCollector): max(fysisk / 2, fysisk - max(4096 MB, 10 % af
|
||||
-- fysisk)).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Standardværdien 2147483647 (int.MaxValue). Reserve til Windows: det største af 4096 MB og 10 %
|
||||
-- (MemoryGuidance.Reserve, fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs
|
||||
-- Medlemmer: ConfigurationCollector.Sql2005, ConfigurationCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:configuration)
|
||||
-- Delt script: SQL Scripts/_collectors/ConfigurationCollector.sql
|
||||
-- ServerCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ServerCollector.cs
|
||||
-- Medlemmer: ServerCollector.BuildSql(version), Db.StartTimeSql(version), ServerCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:server)
|
||||
-- Delt script: SQL Scripts/_collectors/ServerCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : MaxServerMemoryDefaultRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt xp_msver (læser versionsoplysninger), SET-sessionsindstillinger. Intet ændrer
|
||||
-- data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ConfigurationCollector: sp_configure: konfigureret værdi og værdi i brug for alle serverindstillinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ServerCollector: Starttidspunkt, logiske CPU'er, schedulers, NUMA-noder, fysisk hukommelse og virtualisering.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere
|
||||
-- Kilde: ServerCollector.BuildSql(2012+)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_kb / 1024,
|
||||
virtual_machine_type_desc
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og senere 2008 R2-builds
|
||||
-- Kilde: ServerCollector.BuildSql(2008 R2 SP1)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
virtual_machine_type_desc
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og 2008 R2 før SP1
|
||||
-- Kilde: ServerCollector.BuildSql(2008)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
CAST(NULL AS nvarchar(60))
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005
|
||||
-- Kilde: ServerCollector.BuildSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT create_date FROM sys.databases WHERE database_id = 2),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
CAST(NULL AS nvarchar(60))
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: ServerCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): CPU og hukommelse
|
||||
-- Kilde: ServerCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.Sql2000
|
||||
EXEC master.dbo.xp_msver
|
||||
GO
|
||||
145
SQL Scripts/SQLI-CFG-002.sql
Normal file
145
SQL Scripts/SQLI-CFG-002.sql
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-002: max server memory efterlader for lidt til Windows
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-002
|
||||
-- Titel: max server memory efterlader for lidt til Windows
|
||||
-- Alvor: Medium
|
||||
-- Versioner: Alle, hvor fysisk hukommelse kan aflæses (SQL Server 2005+ via sys.dm_os_sys_info, 2000 via xp_msver).
|
||||
-- Ikke relevant på Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om 'max server memory (MB)' er sat så højt, at der er for lidt tilbage til Windows, tråd-stacks og allokeringer
|
||||
-- uden for buffer pool.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis max server memory < 2147483647 (standardværdien er SQLI-CFG-001) og fysisk hukommelse - max server
|
||||
-- memory < halvdelen af reserven, hvor reserven er max(4096 MB, 10 % af fysisk). Fundet anbefaler max(fysisk / 2,
|
||||
-- fysisk - reserven).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Reserve: max(4096 MB, 10 %) (MemoryGuidance.Reserve, fast i koden); fund under halvdelen af reserven.
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs
|
||||
-- Medlemmer: ConfigurationCollector.Sql2005, ConfigurationCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:configuration)
|
||||
-- Delt script: SQL Scripts/_collectors/ConfigurationCollector.sql
|
||||
-- ServerCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ServerCollector.cs
|
||||
-- Medlemmer: ServerCollector.BuildSql(version), Db.StartTimeSql(version), ServerCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:server)
|
||||
-- Delt script: SQL Scripts/_collectors/ServerCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : MaxServerMemoryTooHighRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt xp_msver (læser versionsoplysninger), SET-sessionsindstillinger. Intet ændrer
|
||||
-- data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ConfigurationCollector: sp_configure: konfigureret værdi og værdi i brug for alle serverindstillinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ServerCollector: Starttidspunkt, logiske CPU'er, schedulers, NUMA-noder, fysisk hukommelse og virtualisering.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere
|
||||
-- Kilde: ServerCollector.BuildSql(2012+)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_kb / 1024,
|
||||
virtual_machine_type_desc
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og senere 2008 R2-builds
|
||||
-- Kilde: ServerCollector.BuildSql(2008 R2 SP1)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
virtual_machine_type_desc
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og 2008 R2 før SP1
|
||||
-- Kilde: ServerCollector.BuildSql(2008)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
CAST(NULL AS nvarchar(60))
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005
|
||||
-- Kilde: ServerCollector.BuildSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT create_date FROM sys.databases WHERE database_id = 2),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
CAST(NULL AS nvarchar(60))
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: ServerCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): CPU og hukommelse
|
||||
-- Kilde: ServerCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.Sql2000
|
||||
EXEC master.dbo.xp_msver
|
||||
GO
|
||||
142
SQL Scripts/SQLI-CFG-003.sql
Normal file
142
SQL Scripts/SQLI-CFG-003.sql
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-003: cost threshold for parallelism står på standardværdien 5
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-003
|
||||
-- Titel: cost threshold for parallelism står på standardværdien 5
|
||||
-- Alvor: Medium
|
||||
-- Versioner: Alle (SQL Server 2000 og nyere).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om 'cost threshold for parallelism' står på standardværdien 5, så selv små forespørgsler kører parallelt.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis value_in_use for 'cost threshold for parallelism' = 5, 'max degree of parallelism' <> 1 og cpu_count
|
||||
-- (ServerCollector) > 1. Fix-scriptet i fundet foreslår 50 (køres aldrig automatisk).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Standardværdien 5; anbefalet startværdi 50 (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs
|
||||
-- Medlemmer: ConfigurationCollector.Sql2005, ConfigurationCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:configuration)
|
||||
-- Delt script: SQL Scripts/_collectors/ConfigurationCollector.sql
|
||||
-- ServerCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ServerCollector.cs
|
||||
-- Medlemmer: ServerCollector.BuildSql(version), Db.StartTimeSql(version), ServerCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:server)
|
||||
-- Delt script: SQL Scripts/_collectors/ServerCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : CostThresholdRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt xp_msver (læser versionsoplysninger), SET-sessionsindstillinger. Intet ændrer
|
||||
-- data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ConfigurationCollector: sp_configure: konfigureret værdi og værdi i brug for alle serverindstillinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ServerCollector: Starttidspunkt, logiske CPU'er, schedulers, NUMA-noder, fysisk hukommelse og virtualisering.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere
|
||||
-- Kilde: ServerCollector.BuildSql(2012+)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_kb / 1024,
|
||||
virtual_machine_type_desc
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og senere 2008 R2-builds
|
||||
-- Kilde: ServerCollector.BuildSql(2008 R2 SP1)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
virtual_machine_type_desc
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og 2008 R2 før SP1
|
||||
-- Kilde: ServerCollector.BuildSql(2008)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
CAST(NULL AS nvarchar(60))
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005
|
||||
-- Kilde: ServerCollector.BuildSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT create_date FROM sys.databases WHERE database_id = 2),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
CAST(NULL AS nvarchar(60))
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: ServerCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): CPU og hukommelse
|
||||
-- Kilde: ServerCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.Sql2000
|
||||
EXEC master.dbo.xp_msver
|
||||
GO
|
||||
144
SQL Scripts/SQLI-CFG-004.sql
Normal file
144
SQL Scripts/SQLI-CFG-004.sql
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-004: MAXDOP passer ikke til serverens NUMA-layout
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-004
|
||||
-- Titel: MAXDOP passer ikke til serverens NUMA-layout
|
||||
-- Alvor: Medium
|
||||
-- Versioner: Alle (NUMA-noder tælles fra SQL Server 2008; på 2005/2000 regnes med én node).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om MAXDOP passer til serverens NUMA-layout efter Microsofts vejledning.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- schedulers = antal VISIBLE ONLINE schedulers (ellers cpu_count); noder = antal forskellige parent_node_id (mindst
|
||||
-- 1); pr. node = schedulers / noder. Anbefalet = min(8, pr. node) ved én node; ved flere noder pr. node hvis <= 16,
|
||||
-- ellers min(16, pr. node / 2). Fund hvis schedulers > 1 og enten MAXDOP = 0 og anbefalet < schedulers, eller
|
||||
-- MAXDOP > anbefalet.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Microsofts vejledning (MaxDopRule.Recommended, fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs
|
||||
-- Medlemmer: ConfigurationCollector.Sql2005, ConfigurationCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:configuration)
|
||||
-- Delt script: SQL Scripts/_collectors/ConfigurationCollector.sql
|
||||
-- ServerCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ServerCollector.cs
|
||||
-- Medlemmer: ServerCollector.BuildSql(version), Db.StartTimeSql(version), ServerCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:server)
|
||||
-- Delt script: SQL Scripts/_collectors/ServerCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : MaxDopRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt xp_msver (læser versionsoplysninger), SET-sessionsindstillinger. Intet ændrer
|
||||
-- data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ConfigurationCollector: sp_configure: konfigureret værdi og værdi i brug for alle serverindstillinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ServerCollector: Starttidspunkt, logiske CPU'er, schedulers, NUMA-noder, fysisk hukommelse og virtualisering.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere
|
||||
-- Kilde: ServerCollector.BuildSql(2012+)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_kb / 1024,
|
||||
virtual_machine_type_desc
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og senere 2008 R2-builds
|
||||
-- Kilde: ServerCollector.BuildSql(2008 R2 SP1)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
virtual_machine_type_desc
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og 2008 R2 før SP1
|
||||
-- Kilde: ServerCollector.BuildSql(2008)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
CAST(NULL AS nvarchar(60))
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005
|
||||
-- Kilde: ServerCollector.BuildSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT create_date FROM sys.databases WHERE database_id = 2),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
CAST(NULL AS nvarchar(60))
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: ServerCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): CPU og hukommelse
|
||||
-- Kilde: ServerCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.Sql2000
|
||||
EXEC master.dbo.xp_msver
|
||||
GO
|
||||
89
SQL Scripts/SQLI-CFG-005.sql
Normal file
89
SQL Scripts/SQLI-CFG-005.sql
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-005: Plan cache er fyldt med engangsplaner
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-005
|
||||
-- Titel: Plan cache er fyldt med engangsplaner
|
||||
-- Alvor: Low
|
||||
-- Versioner: SQL Server 2005 og nyere (DynamicManagementViews; indstillingen findes fra 2008 - mangler den, er
|
||||
-- reglen "ikke målbar").
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om plan cache er fyldt med ad hoc-planer, der kun er brugt én gang, mens 'optimize for ad hoc workloads' er slået
|
||||
-- fra.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis 'optimize for ad hoc workloads' value_in_use = 0, og engangs-ad hoc-planer (objtype = Adhoc og
|
||||
-- usecounts = 1) fylder mindst 25 % af plan cache og mindst 100 MB.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Andel >= 25 % og >= 100 MB (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs
|
||||
-- Medlemmer: ConfigurationCollector.Sql2005, ConfigurationCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:configuration)
|
||||
-- Delt script: SQL Scripts/_collectors/ConfigurationCollector.sql
|
||||
-- PlanCacheCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/PlanCacheCollector.cs
|
||||
-- Medlemmer: PlanCacheCollector.Sql
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:plan-cache)
|
||||
-- Delt script: SQL Scripts/_collectors/PlanCacheCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : OptimizeForAdHocRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ConfigurationCollector: sp_configure: konfigureret værdi og værdi i brug for alle serverindstillinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- PlanCacheCollector: Plan cache: antal og størrelse af planer og af ad hoc-planer brugt én gang.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: PlanCacheCollector.Sql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PlanCacheCollector.cs : PlanCacheCollector.Sql
|
||||
SELECT
|
||||
COUNT_BIG(*),
|
||||
ISNULL(SUM(CAST(size_in_bytes AS bigint)), 0) / 1048576.0,
|
||||
ISNULL(SUM(CASE WHEN objtype = N'Adhoc' AND usecounts = 1 THEN 1 ELSE 0 END), 0),
|
||||
ISNULL(SUM(CASE WHEN objtype = N'Adhoc' AND usecounts = 1 THEN CAST(size_in_bytes AS bigint) ELSE 0 END), 0) / 1048576.0
|
||||
FROM sys.dm_exec_cached_plans
|
||||
GO
|
||||
65
SQL Scripts/SQLI-CFG-006.sql
Normal file
65
SQL Scripts/SQLI-CFG-006.sql
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-006: Priority boost er slået til
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-006
|
||||
-- Titel: Priority boost er slået til
|
||||
-- Alvor: High
|
||||
-- Versioner: Alle (SQL Server 2000 og nyere). Ikke relevant på Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om 'priority boost' er slået til. Det kan udsulte Windows og cluster-tjenester og er forældet.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis value_in_use for 'priority boost' <> 0.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen (alt andet end 0 er et fund).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- Ingen ekstra rettighed: public må læse dette (SERVERPROPERTY, sys.configurations, DBCC TRACESTATUS, xp_msver).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs
|
||||
-- Medlemmer: ConfigurationCollector.Sql2005, ConfigurationCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:configuration)
|
||||
-- Delt script: SQL Scripts/_collectors/ConfigurationCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : SimpleConfigurationRules.Create
|
||||
-- (ConfigurationOptionRule "priority boost")
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ConfigurationCollector: sp_configure: konfigureret værdi og værdi i brug for alle serverindstillinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
66
SQL Scripts/SQLI-CFG-007.sql
Normal file
66
SQL Scripts/SQLI-CFG-007.sql
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-007: Lightweight pooling (fiber mode) er slået til
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-007
|
||||
-- Titel: Lightweight pooling (fiber mode) er slået til
|
||||
-- Alvor: High
|
||||
-- Versioner: Alle (SQL Server 2000 og nyere). Ikke relevant på Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om 'lightweight pooling' (fiber mode) er slået til. Det understøttes ikke af bl.a. CLR og distribuerede
|
||||
-- transaktioner.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis value_in_use for 'lightweight pooling' <> 0.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen (alt andet end 0 er et fund).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- Ingen ekstra rettighed: public må læse dette (SERVERPROPERTY, sys.configurations, DBCC TRACESTATUS, xp_msver).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs
|
||||
-- Medlemmer: ConfigurationCollector.Sql2005, ConfigurationCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:configuration)
|
||||
-- Delt script: SQL Scripts/_collectors/ConfigurationCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : SimpleConfigurationRules.Create
|
||||
-- (ConfigurationOptionRule "lightweight pooling")
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ConfigurationCollector: sp_configure: konfigureret værdi og værdi i brug for alle serverindstillinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
66
SQL Scripts/SQLI-CFG-008.sql
Normal file
66
SQL Scripts/SQLI-CFG-008.sql
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-008: xp_cmdshell er slået til
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-008
|
||||
-- Titel: xp_cmdshell er slået til
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere (på 2000 findes indstillingen ikke i sp_configure: "ikke målbar"). Ikke
|
||||
-- relevant på Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om xp_cmdshell er slået til, så T-SQL kan køre vilkårlige Windows-kommandoer med tjenestekontoens rettigheder.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis value_in_use for 'xp_cmdshell' <> 0.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen (alt andet end 0 er et fund).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- Ingen ekstra rettighed: public må læse dette (SERVERPROPERTY, sys.configurations, DBCC TRACESTATUS, xp_msver).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs
|
||||
-- Medlemmer: ConfigurationCollector.Sql2005, ConfigurationCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:configuration)
|
||||
-- Delt script: SQL Scripts/_collectors/ConfigurationCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : SimpleConfigurationRules.Create
|
||||
-- (ConfigurationOptionRule "xp_cmdshell")
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ConfigurationCollector: sp_configure: konfigureret værdi og værdi i brug for alle serverindstillinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
91
SQL Scripts/SQLI-CFG-009.sql
Normal file
91
SQL Scripts/SQLI-CFG-009.sql
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-009: Backup-komprimering er ikke standard
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-009
|
||||
-- Titel: Backup-komprimering er ikke standard
|
||||
-- Alvor: Low
|
||||
-- Versioner: SQL Server 2008 og nyere (indstillingen findes ikke før: "ikke målbar"). Bestået på Express
|
||||
-- (EngineEdition 4 fra InstanceProbe), som ikke kan komprimere backups. Ikke relevant på Azure SQL
|
||||
-- Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om backup-komprimering er standard, så hvert backup-job ikke selv skal huske WITH COMPRESSION.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis value_in_use for 'backup compression default' = 0 og udgaven ikke er Express.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- Ingen ekstra rettighed: public må læse dette (SERVERPROPERTY, sys.configurations, DBCC TRACESTATUS, xp_msver).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs
|
||||
-- Medlemmer: ConfigurationCollector.Sql2005, ConfigurationCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:configuration)
|
||||
-- Delt script: SQL Scripts/_collectors/ConfigurationCollector.sql
|
||||
-- InstanceProbe
|
||||
-- Fil: src/SQLInsight.Connectivity/InstanceProbe.cs
|
||||
-- Medlemmer: InstanceProbe.Query
|
||||
-- Interval: én gang, når agenten forbinder til instansen
|
||||
-- Delt script: SQL Scripts/_collectors/InstanceProbe.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : SimpleConfigurationRules.Create
|
||||
-- (ConfigurationOptionRule "backup compression default")
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ConfigurationCollector: sp_configure: konfigureret værdi og værdi i brug for alle serverindstillinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- InstanceProbe: Registrering af instansen: version, udgave, cluster og Always On. Køres, når agenten forbinder, og
|
||||
-- bestemmer hvilke varianter og regler der bruges.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner (SQL Server 2000 og nyere)
|
||||
-- Kilde: InstanceProbe.Query
|
||||
-- Kode: src/SQLInsight.Connectivity/InstanceProbe.cs : InstanceProbe.Query
|
||||
SELECT
|
||||
CAST(SERVERPROPERTY('ServerName') AS nvarchar(256)),
|
||||
CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductUpdateLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('Edition') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('EngineEdition') AS int),
|
||||
CAST(SERVERPROPERTY('IsClustered') AS int),
|
||||
CAST(SERVERPROPERTY('IsHadrEnabled') AS int)
|
||||
GO
|
||||
66
SQL Scripts/SQLI-CFG-010.sql
Normal file
66
SQL Scripts/SQLI-CFG-010.sql
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-010: Dedicated Admin Connection kan kun bruges lokalt
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-010
|
||||
-- Titel: Dedicated Admin Connection kan kun bruges lokalt
|
||||
-- Alvor: Low
|
||||
-- Versioner: SQL Server 2005 og nyere (på 2000 findes indstillingen ikke: "ikke målbar"). Ikke relevant på Azure
|
||||
-- SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om Dedicated Admin Connection (DAC) kun kan bruges fra selve serveren.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis value_in_use for 'remote admin connections' = 0.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- Ingen ekstra rettighed: public må læse dette (SERVERPROPERTY, sys.configurations, DBCC TRACESTATUS, xp_msver).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs
|
||||
-- Medlemmer: ConfigurationCollector.Sql2005, ConfigurationCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:configuration)
|
||||
-- Delt script: SQL Scripts/_collectors/ConfigurationCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : SimpleConfigurationRules.Create
|
||||
-- (ConfigurationOptionRule "remote admin connections")
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ConfigurationCollector: sp_configure: konfigureret værdi og værdi i brug for alle serverindstillinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
66
SQL Scripts/SQLI-CFG-011.sql
Normal file
66
SQL Scripts/SQLI-CFG-011.sql
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-011: Konfigurationsændringer venter på RECONFIGURE eller genstart
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-011
|
||||
-- Titel: Konfigurationsændringer venter på RECONFIGURE eller genstart
|
||||
-- Alvor: Low
|
||||
-- Versioner: Alle (SQL Server 2000 og nyere).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om indstillinger er ændret med sp_configure uden RECONFIGURE eller genstart, så de træder i kraft på et uventet
|
||||
-- tidspunkt.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund med alle indstillinger, hvor value (konfigureret) <> value_in_use (i brug). 'min server memory (MB)'
|
||||
-- ignoreres (konfigureret 0, mens SQL Server rapporterer det effektive minimum).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- Ingen ekstra rettighed: public må læse dette (SERVERPROPERTY, sys.configurations, DBCC TRACESTATUS, xp_msver).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs
|
||||
-- Medlemmer: ConfigurationCollector.Sql2005, ConfigurationCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:configuration)
|
||||
-- Delt script: SQL Scripts/_collectors/ConfigurationCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : PendingConfigurationRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ConfigurationCollector: sp_configure: konfigureret værdi og værdi i brug for alle serverindstillinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
81
SQL Scripts/SQLI-CFG-012.sql
Normal file
81
SQL Scripts/SQLI-CFG-012.sql
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-012: Deadlocks bliver ikke registreret
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-012
|
||||
-- Titel: Deadlocks bliver ikke registreret
|
||||
-- Alvor: Low
|
||||
-- Versioner: Har kun betydning på SQL Server 2000 og 2005: fra 2008 (system_health-sessionen, udledt af versionen
|
||||
-- fra InstanceProbe) er reglen altid bestået.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om deadlocks kan analyseres bagefter på versioner uden system_health.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Bestået hvis instansen har system_health (2008+). Ellers fund, hvis hverken trace flag 1222 eller 1204 er slået
|
||||
-- til globalt (DBCC TRACESTATUS(-1): Status = 1 og Global = 1).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- Ingen ekstra rettighed: public må læse dette (SERVERPROPERTY, sys.configurations, DBCC TRACESTATUS, xp_msver).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- TraceFlagCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/TraceFlagCollector.cs
|
||||
-- Medlemmer: TraceFlagCollector.Sql
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:trace-flags)
|
||||
-- Delt script: SQL Scripts/_collectors/TraceFlagCollector.sql
|
||||
-- InstanceProbe
|
||||
-- Fil: src/SQLInsight.Connectivity/InstanceProbe.cs
|
||||
-- Medlemmer: InstanceProbe.Query
|
||||
-- Interval: én gang, når agenten forbinder til instansen
|
||||
-- Delt script: SQL Scripts/_collectors/InstanceProbe.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : DeadlockTraceFlagRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt DBCC TRACESTATUS (læser trace flags), SET-sessionsindstillinger. Intet ændrer
|
||||
-- data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- TraceFlagCollector: De globalt slåede trace flags.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner (SQL Server 2000 og nyere)
|
||||
-- Kilde: TraceFlagCollector.Sql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TraceFlagCollector.cs : TraceFlagCollector.Sql
|
||||
DBCC TRACESTATUS(-1) WITH NO_INFOMSGS
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- InstanceProbe: Registrering af instansen: version, udgave, cluster og Always On. Køres, når agenten forbinder, og
|
||||
-- bestemmer hvilke varianter og regler der bruges.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner (SQL Server 2000 og nyere)
|
||||
-- Kilde: InstanceProbe.Query
|
||||
-- Kode: src/SQLInsight.Connectivity/InstanceProbe.cs : InstanceProbe.Query
|
||||
SELECT
|
||||
CAST(SERVERPROPERTY('ServerName') AS nvarchar(256)),
|
||||
CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductUpdateLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('Edition') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('EngineEdition') AS int),
|
||||
CAST(SERVERPROPERTY('IsClustered') AS int),
|
||||
CAST(SERVERPROPERTY('IsHadrEnabled') AS int)
|
||||
GO
|
||||
121
SQL Scripts/SQLI-CFG-013.sql
Normal file
121
SQL Scripts/SQLI-CFG-013.sql
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CFG-013: Konfiguration ændret
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CFG-013
|
||||
-- Titel: Konfiguration ændret
|
||||
-- Alvor: Info
|
||||
-- Versioner: Alle. Tjenestekonti kun fra SQL Server 2008 R2 SP1 (sys.dm_server_services).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om nogen har ændret en sp_configure-indstilling, et globalt trace flag eller en tjenestekonto. Information, så
|
||||
-- ændringen er synlig.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- InstanceConfigurationCollector bygger et "fingeraftryk" af sp_configure (value_in_use), globale trace flags,
|
||||
-- tjenester og konti, version, udgave, collation, tempdb-filer m.m. og sammenligner med forrige måling (gemt i
|
||||
-- agentens repository, så en ændring mens agenten var nede også ses). Ændringer i områderne sp_configure, trace
|
||||
-- flag og tjenestekonto inden for de seneste 24 timer giver ét Info-fund pr. ændring. Alt sker i C#; SQL'en læser
|
||||
-- kun de nuværende værdier.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Fundet holdes åbent i 24 timer (ConfigurationFingerprint.RecentWindow, fast i koden).
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- InstanceConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs
|
||||
-- Medlemmer: InstanceConfigurationCollector.PropertiesSql, InstanceConfigurationCollector.TempdbSql,
|
||||
-- InstanceConfigurationCollector.ColumnsSql, InstanceConfigurationCollector.BuildServicesSql(true),
|
||||
-- InstanceConfigurationCollector.BuildServicesSql(false), InstanceConfigurationCollector.MemoryModelSql
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:instance-config)
|
||||
-- Delt script: SQL Scripts/_collectors/InstanceConfigurationCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Configuration/ConfigurationRules.cs : ConfigurationChangedRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt DBCC TRACESTATUS (læser trace flags), SET-sessionsindstillinger. Intet ændrer
|
||||
-- data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- InstanceConfigurationCollector: Instansens opsætning til konfigurationssiden og ændringsloggen: egenskaber,
|
||||
-- tempdb-filer, tjenester og konti, Instant File Initialization, memory model, sp_configure og trace flags.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere (samme forespørgsel som ConfigurationCollector)
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti) (samme forespørgsel som ConfigurationCollector)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner (SQL Server 2000 og nyere) (samme forespørgsel som TraceFlagCollector)
|
||||
-- Kilde: TraceFlagCollector.Sql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TraceFlagCollector.cs : TraceFlagCollector.Sql
|
||||
DBCC TRACESTATUS(-1) WITH NO_INFOMSGS
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner
|
||||
-- Kilde: InstanceConfigurationCollector.PropertiesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.PropertiesSql
|
||||
SELECT CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)), CAST(SERVERPROPERTY('ProductLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('Edition') AS nvarchar(128)), CAST(SERVERPROPERTY('Collation') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('InstanceDefaultDataPath') AS nvarchar(260)), CAST(SERVERPROPERTY('InstanceDefaultLogPath') AS nvarchar(260))
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: InstanceConfigurationCollector.TempdbSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.TempdbSql
|
||||
SELECT name, type_desc, CAST(size AS bigint) / 128, growth, is_percent_growth, max_size
|
||||
FROM sys.master_files WHERE database_id = 2 ORDER BY file_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og nyere
|
||||
-- Kilde: InstanceConfigurationCollector.ColumnsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.ColumnsSql
|
||||
SELECT COL_LENGTH('sys.dm_server_services', 'instant_file_initialization_enabled'), COL_LENGTH('sys.dm_os_sys_info', 'sql_memory_model_desc')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og nyere, builds med kolonnen instant_file_initialization_enabled (se ColumnsSql)
|
||||
-- Kilde: InstanceConfigurationCollector.BuildServicesSql(med IFI)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.BuildServicesSql(true)
|
||||
SELECT servicename, service_account, startup_type_desc, status_desc, instant_file_initialization_enabled FROM sys.dm_server_services
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og nyere, builds uden kolonnen instant_file_initialization_enabled
|
||||
-- Kilde: InstanceConfigurationCollector.BuildServicesSql(uden IFI)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.BuildServicesSql(false)
|
||||
SELECT servicename, service_account, startup_type_desc, status_desc, CAST(NULL AS nvarchar(1)) FROM sys.dm_server_services
|
||||
GO
|
||||
|
||||
-- Variant: Builds med kolonnen sql_memory_model_desc (se ColumnsSql)
|
||||
-- Kilde: InstanceConfigurationCollector.MemoryModelSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.MemoryModelSql
|
||||
SELECT sql_memory_model_desc FROM sys.dm_os_sys_info
|
||||
GO
|
||||
77
SQL Scripts/SQLI-CPU-001.sql
Normal file
77
SQL Scripts/SQLI-CPU-001.sql
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CPU-001: Vedvarende højt CPU-forbrug
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CPU-001
|
||||
-- Titel: Vedvarende højt CPU-forbrug
|
||||
-- Alvor: SQL Server: Medium fra 75 %, High fra 90 %. Andre processer: Medium.
|
||||
-- Versioner: SQL Server 2005 og nyere. "Andre processer" kan ikke måles på Linux (host_platform fra SQL Server
|
||||
-- 2017) og Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om CPU'en har været vedvarende høj, opdelt i SQL Servers eget forbrug og andre processers.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Scheduler monitor skriver én post i minuttet (ProcessUtilization = SQL Server, SystemIdle = ledig). Reglen bruger
|
||||
-- de seneste op til 15 poster (kræver mindst 5). Fund 1: gennemsnitlig ProcessUtilization >= 75 %. Fund 2:
|
||||
-- gennemsnitlig andel til andre processer (100 - SystemIdle - ProcessUtilization) >= 25 %.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 15 minutter (CpuRule.Minutes); 75 % / 90 % for SQL Server; 25 % for andre (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- CpuCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/CpuCollector.cs
|
||||
-- Medlemmer: CpuCollector.Sql, CpuCollector.HostPlatformSql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:cpu)
|
||||
-- Delt script: SQL Scripts/_collectors/CpuCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/ResourceRules.cs : CpuRule.Evaluate
|
||||
--
|
||||
-- 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 (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CpuCollector: SQL Servers og systemets CPU-forbrug pr. minut (scheduler monitor ring buffer, op til 60 minutter).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: CpuCollector.Sql
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/CpuCollector.cs : CpuCollector.Sql
|
||||
DECLARE @now_ticks bigint;
|
||||
SELECT @now_ticks = ms_ticks FROM sys.dm_os_sys_info;
|
||||
SELECT TOP (60)
|
||||
DATEADD(second, CAST((rb.[timestamp] - @now_ticks) / 1000 AS int), GETUTCDATE()),
|
||||
rb.record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]', 'int'),
|
||||
rb.record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int')
|
||||
FROM (
|
||||
SELECT [timestamp], CONVERT(xml, record) AS record
|
||||
FROM sys.dm_os_ring_buffers
|
||||
WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR' AND record LIKE N'%<SystemHealth>%'
|
||||
) rb
|
||||
ORDER BY rb.[timestamp] DESC
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2017 og nyere (Windows eller Linux)
|
||||
-- Kilde: CpuCollector.HostPlatformSql
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/CpuCollector.cs : CpuCollector.HostPlatformSql
|
||||
SELECT host_platform FROM sys.dm_os_host_info
|
||||
GO
|
||||
130
SQL Scripts/SQLI-CPU-002.sql
Normal file
130
SQL Scripts/SQLI-CPU-002.sql
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-CPU-002: Sætning kører næsten uafbrudt
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-CPU-002
|
||||
-- Titel: Sætning kører næsten uafbrudt
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en sætning i praksis holder en CPU-kerne beskæftiget hele tiden.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For hver sætning (query_hash; på 2005 sql_handle + offsets) i top SQL: aktivitet = total_worker_time /
|
||||
-- (last_execution_time - creation_time) i procent af én kerne. Fund (op til 5, højeste først) for sætninger, der
|
||||
-- har kørt inden for de seneste 15 minutter, har ligget mindst 1 time i plan cache og har aktivitet over grænsen.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:TopSql:ActivityThresholdPercent, standard 50 (%); mindst 1 time i plan cache
|
||||
-- (ConstantActivityRule.MinimumLifetime, fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- QueryStatsCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/QueryStatsCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), QueryStatsCollector.Sql2008 via SqlFor(version, since: null),
|
||||
-- QueryStatsCollector.Sql2005 via SqlFor(version, since: null), QueryStatsCollector.ServerTimeSql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:query-stats)
|
||||
-- Delt script: SQL Scripts/_collectors/QueryStatsCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/OperationRules.cs : ConstantActivityRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- QueryStatsCollector: Top SQL: de tungeste sætninger (top 50 efter CPU, varighed, læsninger og antal) blandt dem,
|
||||
-- der har kørt siden forrige måling. Ingen planer, tekst afkortet.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt
|
||||
-- Kilde: QueryStatsCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: QueryStatsCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere (første kørsel: de seneste 15 minutter)
|
||||
-- Kilde: QueryStatsCollector.SqlFor(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/QueryStatsCollector.cs : QueryStatsCollector.Sql2008 via SqlFor(version, since: null)
|
||||
WITH s AS (
|
||||
SELECT qs.query_hash AS k,
|
||||
SUM(qs.execution_count) AS execs, SUM(qs.total_worker_time) AS cpu, SUM(qs.total_elapsed_time) AS elapsed,
|
||||
SUM(qs.total_logical_reads) AS lreads, SUM(qs.total_physical_reads) AS preads, SUM(qs.total_logical_writes) AS writes,
|
||||
MIN(qs.creation_time) AS created, MAX(qs.last_execution_time) AS last_exec
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
GROUP BY qs.query_hash
|
||||
HAVING MAX(qs.last_execution_time) >= DATEADD(minute, -15, GETDATE())),
|
||||
t AS (
|
||||
SELECT k FROM (SELECT TOP (50) k FROM s ORDER BY cpu DESC) a
|
||||
UNION SELECT k FROM (SELECT TOP (50) k FROM s ORDER BY elapsed DESC) b
|
||||
UNION SELECT k FROM (SELECT TOP (50) k FROM s ORDER BY lreads DESC) c
|
||||
UNION SELECT k FROM (SELECT TOP (50) k FROM s ORDER BY execs DESC) d)
|
||||
SELECT CONVERT(varchar(20), s.k, 1), s.execs, s.cpu, s.elapsed, s.lreads, s.preads, s.writes, s.created, s.last_exec,
|
||||
DB_NAME(COALESCE(st.dbid, pa.dbid)),
|
||||
CAST(SUBSTRING(st.text, r.statement_start_offset / 2 + 1,
|
||||
CASE WHEN r.statement_end_offset = -1 THEN 4000
|
||||
ELSE (r.statement_end_offset - r.statement_start_offset) / 2 + 1 END) AS nvarchar(4000)),
|
||||
GETDATE()
|
||||
FROM s JOIN t ON t.k = s.k
|
||||
OUTER APPLY (SELECT TOP (1) q.sql_handle, q.plan_handle, q.statement_start_offset, q.statement_end_offset
|
||||
FROM sys.dm_exec_query_stats q WHERE q.query_hash = s.k ORDER BY q.last_execution_time DESC) r
|
||||
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) st
|
||||
OUTER APPLY (SELECT CAST(a.value AS int) AS dbid FROM sys.dm_exec_plan_attributes(r.plan_handle) a WHERE a.attribute = N'dbid') pa
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 (første kørsel: de seneste 15 minutter)
|
||||
-- Kilde: QueryStatsCollector.SqlFor(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/QueryStatsCollector.cs : QueryStatsCollector.Sql2005 via SqlFor(version, since: null)
|
||||
WITH s AS (
|
||||
SELECT qs.sql_handle AS h, qs.statement_start_offset AS so, qs.statement_end_offset AS eo,
|
||||
SUM(qs.execution_count) AS execs, SUM(qs.total_worker_time) AS cpu, SUM(qs.total_elapsed_time) AS elapsed,
|
||||
SUM(qs.total_logical_reads) AS lreads, SUM(qs.total_physical_reads) AS preads, SUM(qs.total_logical_writes) AS writes,
|
||||
MIN(qs.creation_time) AS created, MAX(qs.last_execution_time) AS last_exec
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
GROUP BY qs.sql_handle, qs.statement_start_offset, qs.statement_end_offset
|
||||
HAVING MAX(qs.last_execution_time) >= DATEADD(minute, -15, GETDATE())),
|
||||
t AS (
|
||||
SELECT h, so, eo FROM (SELECT TOP (50) h, so, eo FROM s ORDER BY cpu DESC) a
|
||||
UNION SELECT h, so, eo FROM (SELECT TOP (50) h, so, eo FROM s ORDER BY elapsed DESC) b
|
||||
UNION SELECT h, so, eo FROM (SELECT TOP (50) h, so, eo FROM s ORDER BY lreads DESC) c
|
||||
UNION SELECT h, so, eo FROM (SELECT TOP (50) h, so, eo FROM s ORDER BY execs DESC) d)
|
||||
SELECT sys.fn_varbintohexstr(s.h) + ':' + CAST(s.so AS varchar(12)) + ':' + CAST(s.eo AS varchar(12)),
|
||||
s.execs, s.cpu, s.elapsed, s.lreads, s.preads, s.writes, s.created, s.last_exec,
|
||||
DB_NAME(COALESCE(st.dbid, pa.dbid)),
|
||||
CAST(SUBSTRING(st.text, s.so / 2 + 1, CASE WHEN s.eo = -1 THEN 4000 ELSE (s.eo - s.so) / 2 + 1 END) AS nvarchar(4000)),
|
||||
GETDATE()
|
||||
FROM s JOIN t ON t.h = s.h AND t.so = s.so AND t.eo = s.eo
|
||||
OUTER APPLY sys.dm_exec_sql_text(s.h) st
|
||||
OUTER APPLY (SELECT TOP (1) q.plan_handle FROM sys.dm_exec_query_stats q
|
||||
WHERE q.sql_handle = s.h AND q.statement_start_offset = s.so AND q.statement_end_offset = s.eo) r
|
||||
OUTER APPLY (SELECT CAST(a.value AS int) AS dbid FROM sys.dm_exec_plan_attributes(r.plan_handle) a WHERE a.attribute = N'dbid') pa
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner, kun når ingen sætning har kørt siden sidst
|
||||
-- Kilde: QueryStatsCollector.ServerTimeSql
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/QueryStatsCollector.cs : QueryStatsCollector.ServerTimeSql
|
||||
SELECT GETDATE()
|
||||
GO
|
||||
222
SQL Scripts/SQLI-DB-001.sql
Normal file
222
SQL Scripts/SQLI-DB-001.sql
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-001: Database er ikke tilgængelig
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-001
|
||||
-- Titel: Database er ikke tilgængelig
|
||||
-- Alvor: Critical for SUSPECT, RECOVERY_PENDING og EMERGENCY; Low for OFFLINE.
|
||||
-- Versioner: Alle (SQL Server 2000 via DATABASEPROPERTYEX(..., 'Status')).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en database er utilgængelig.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund pr. database (undtagen tempdb), hvis state_desc er SUSPECT, RECOVERY_PENDING, EMERGENCY eller OFFLINE.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : DatabaseStateRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
223
SQL Scripts/SQLI-DB-002.sql
Normal file
223
SQL Scripts/SQLI-DB-002.sql
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-002: AUTO_SHRINK er slået til
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-002
|
||||
-- Titel: AUTO_SHRINK er slået til
|
||||
-- Alvor: High
|
||||
-- Versioner: Alle (SQL Server 2000 og nyere).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om AUTO_SHRINK er slået til. Det fragmenterer indexes og koster CPU og I/O i en evig cyklus.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund pr. ONLINE database med is_auto_shrink_on = 1.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : SimpleDatabaseRules.Create (DatabaseSettingRule
|
||||
-- "SQLI-DB-002")
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
223
SQL Scripts/SQLI-DB-003.sql
Normal file
223
SQL Scripts/SQLI-DB-003.sql
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-003: AUTO_CLOSE er slået til
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-003
|
||||
-- Titel: AUTO_CLOSE er slået til
|
||||
-- Alvor: Medium
|
||||
-- Versioner: Alle (SQL Server 2000 og nyere).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om AUTO_CLOSE er slået til, så databasen lukkes og plan cache tømmes, når sidste forbindelse slipper den.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund pr. ONLINE database med is_auto_close_on = 1.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : SimpleDatabaseRules.Create (DatabaseSettingRule
|
||||
-- "SQLI-DB-003")
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
224
SQL Scripts/SQLI-DB-004.sql
Normal file
224
SQL Scripts/SQLI-DB-004.sql
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-004: Sidekontrol er ikke CHECKSUM
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-004
|
||||
-- Titel: Sidekontrol er ikke CHECKSUM
|
||||
-- Alvor: Medium
|
||||
-- Versioner: Alle (på SQL Server 2000 rapporteres TORN_PAGE_DETECTION eller NONE, da CHECKSUM først findes fra
|
||||
-- 2005).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om sidekontrollen (PAGE_VERIFY) er andet end CHECKSUM, så korruption fra storage ikke opdages ved læsning.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund pr. ONLINE database, hvor page_verify_option_desc ikke er NULL og ikke er CHECKSUM.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : SimpleDatabaseRules.Create (DatabaseSettingRule
|
||||
-- "SQLI-DB-004")
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
223
SQL Scripts/SQLI-DB-005.sql
Normal file
223
SQL Scripts/SQLI-DB-005.sql
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-005: TRUSTWORTHY er slået til
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-005
|
||||
-- Titel: TRUSTWORTHY er slået til
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere (på 2000 rapporterer collectoren altid 0).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om TRUSTWORTHY er slået til, hvilket kan lade en db_owner blive sysadmin.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund pr. ONLINE database med is_trustworthy_on = 1, undtagen msdb (hvor det er Microsofts standard).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : SimpleDatabaseRules.Create (DatabaseSettingRule
|
||||
-- "SQLI-DB-005")
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
247
SQL Scripts/SQLI-DB-006.sql
Normal file
247
SQL Scripts/SQLI-DB-006.sql
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-006: Database kører med et ældre compatibility level
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-006
|
||||
-- Titel: Database kører med et ældre compatibility level
|
||||
-- Alvor: Low
|
||||
-- Versioner: Alle.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en brugerdatabase kører med et ældre compatibility level end instansens eget.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Instansens niveau = hovedversion (fra ProductVersion i InstanceProbe) x 10, fx 160 for SQL Server 2022. Ét fund
|
||||
-- pr. ONLINE brugerdatabase (ikke master, model, msdb, tempdb) med compatibility_level under det.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- InstanceProbe
|
||||
-- Fil: src/SQLInsight.Connectivity/InstanceProbe.cs
|
||||
-- Medlemmer: InstanceProbe.Query
|
||||
-- Interval: én gang, når agenten forbinder til instansen
|
||||
-- Delt script: SQL Scripts/_collectors/InstanceProbe.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : CompatibilityLevelRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- InstanceProbe: Registrering af instansen: version, udgave, cluster og Always On. Køres, når agenten forbinder, og
|
||||
-- bestemmer hvilke varianter og regler der bruges.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner (SQL Server 2000 og nyere)
|
||||
-- Kilde: InstanceProbe.Query
|
||||
-- Kode: src/SQLInsight.Connectivity/InstanceProbe.cs : InstanceProbe.Query
|
||||
SELECT
|
||||
CAST(SERVERPROPERTY('ServerName') AS nvarchar(256)),
|
||||
CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductUpdateLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('Edition') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('EngineEdition') AS int),
|
||||
CAST(SERVERPROPERTY('IsClustered') AS int),
|
||||
CAST(SERVERPROPERTY('IsHadrEnabled') AS int)
|
||||
GO
|
||||
225
SQL Scripts/SQLI-DB-007.sql
Normal file
225
SQL Scripts/SQLI-DB-007.sql
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-007: Database mangler en nylig fuld backup
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-007
|
||||
-- Titel: Database mangler en nylig fuld backup
|
||||
-- Alvor: Critical hvis aldrig backet op; High hvis ældre end 7 dage; Medium hvis databasen er i en availability
|
||||
-- group (backup kan være taget på en anden replika).
|
||||
-- Versioner: Alle. Ikke relevant på Azure SQL Managed Instance (Azure tager backup).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en database mangler en nylig fuld backup.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For hver ONLINE database, der ikke er mirror/AG-sekundær, ikke er model og er mindst 1 dag gammel: fund hvis
|
||||
-- seneste fulde backup (msdb.dbo.backupset type 'D', taget efter databasens create_date - 1 sekund, omregnet til
|
||||
-- UTC) mangler eller er ældre end 7 dage.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 7 dage (FullBackupRule.MaxAge, fast i koden); databaser yngre end 1 dag springes over.
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : FullBackupRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
225
SQL Scripts/SQLI-DB-008.sql
Normal file
225
SQL Scripts/SQLI-DB-008.sql
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-008: Database i FULL recovery uden log-backups
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-008
|
||||
-- Titel: Database i FULL recovery uden log-backups
|
||||
-- Alvor: High; Medium hvis databasen er i en availability group.
|
||||
-- Versioner: Alle. Ikke relevant på Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en database i FULL eller BULK_LOGGED recovery mangler log-backups, så loggen vokser og point-in-time restore
|
||||
-- går tabt.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund for ONLINE databaser i FULL/BULK_LOGGED, der ikke er mirror/AG-sekundær, ikke er read-only, ikke er model og
|
||||
-- HAR haft en fuld backup (før den første fulde backup trunkeres loggen som i SIMPLE), når seneste log-backup
|
||||
-- (backupset type 'L') mangler eller er ældre end 24 timer.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 24 timer (LogBackupRule.MaxAge, fast i koden).
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : LogBackupRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
225
SQL Scripts/SQLI-DB-009.sql
Normal file
225
SQL Scripts/SQLI-DB-009.sql
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-009: DBCC CHECKDB er ikke kørt for nylig
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-009
|
||||
-- Titel: DBCC CHECKDB er ikke kørt for nylig
|
||||
-- Alvor: High hvis aldrig kørt eller ældre end 30 dage; ellers Medium.
|
||||
-- Versioner: SQL Server 2016 SP2 og nyere (DATABASEPROPERTYEX(..., 'LastGoodCheckDbTime')). Ældre versioner: "tjek
|
||||
-- manuelt" (DBCC DBINFO ... WITH TABLERESULTS, dbi_dbccLastKnownGood, kræver sysadmin). Ikke relevant på
|
||||
-- Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om DBCC CHECKDB ikke er kørt fejlfrit for nylig.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For hver ONLINE database, der er mindst 7 dage gammel og har en LastGoodCheckDbTime: fund hvis tiden er
|
||||
-- 1900-01-01 (aldrig) eller ældre end 7 dage.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 7 dage (CheckDbRule.MaxAge); High over 30 dage (fast i koden).
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : CheckDbRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
56
SQL Scripts/SQLI-DB-010.sql
Normal file
56
SQL Scripts/SQLI-DB-010.sql
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-010: Korrupte sider registreret i suspect_pages
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-010
|
||||
-- Titel: Korrupte sider registreret i suspect_pages
|
||||
-- Alvor: Critical
|
||||
-- Versioner: SQL Server 2005 og nyere (msdb.dbo.suspect_pages).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om SQL Server har registreret korrupte sider (fejl 823/824/825) i msdb.dbo.suspect_pages.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Rækker, der ikke er løst (event_type 1, 2 og 3; 4 = gendannet, 5 = repareret og 7 = deallokeret tæller ikke),
|
||||
-- grupperes pr. database: ét fund pr. database med op til 20 sider som målinger.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- USE msdb; GRANT SELECT ON dbo.suspect_pages TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- SuspectPageCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/SuspectPageCollector.cs
|
||||
-- Medlemmer: SuspectPageCollector.Sql
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:suspect-pages)
|
||||
-- Delt script: SQL Scripts/_collectors/SuspectPageCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : SuspectPagesRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- SuspectPageCollector: Sider, SQL Server har registreret som korrupte (msdb.dbo.suspect_pages).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: SuspectPageCollector.Sql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/SuspectPageCollector.cs : SuspectPageCollector.Sql
|
||||
SELECT ISNULL(DB_NAME(database_id), CAST(database_id AS nvarchar(20))), file_id, page_id, event_type, error_count, last_update_date
|
||||
FROM msdb.dbo.suspect_pages
|
||||
GO
|
||||
223
SQL Scripts/SQLI-DB-011.sql
Normal file
223
SQL Scripts/SQLI-DB-011.sql
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-011: Transaktionsloggen har for mange VLF'er
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-011
|
||||
-- Titel: Transaktionsloggen har for mange VLF'er
|
||||
-- Alvor: Medium; High over 10.000 VLF'er.
|
||||
-- Versioner: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info). Ældre: "tjek manuelt" med DBCC LOGINFO (sysadmin).
|
||||
-- Ikke relevant på Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om transaktionsloggen har så mange virtuelle logfiler, at recovery, restore og log-backups bliver langsomme.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund pr. ONLINE database med flere end 1.000 VLF'er (COUNT(*) fra sys.dm_db_log_info).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 1.000 (VirtualLogFileRule.Threshold); High over 10 x grænsen (fast i koden).
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : VirtualLogFileRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
223
SQL Scripts/SQLI-DB-012.sql
Normal file
223
SQL Scripts/SQLI-DB-012.sql
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-012: Uhensigtsmæssig autogrowth
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-012
|
||||
-- Titel: Uhensigtsmæssig autogrowth
|
||||
-- Alvor: Low
|
||||
-- Versioner: Alle. Ikke relevant på Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om data- og logfiler har en autogrowth, der giver mange eller uforudsigelige vækster.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For hver fil på mindst 1024 MB med autogrowth > 0 i ONLINE databaser: fund hvis væksten er i procent, eller hvis
|
||||
-- den er under 64 MB.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Filstørrelse >= 1024 MB; fast vækst under 64 MB (fast i koden).
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : FileGrowthRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
223
SQL Scripts/SQLI-DB-013.sql
Normal file
223
SQL Scripts/SQLI-DB-013.sql
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-013: Databasefil nærmer sig sin maksimale størrelse
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-013
|
||||
-- Titel: Databasefil nærmer sig sin maksimale størrelse
|
||||
-- Alvor: High fra 90 %; Critical når filen har nået MAXSIZE.
|
||||
-- Versioner: Alle. Ikke relevant på Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en databasefil nærmer sig sin MAXSIZE, så ændringer snart fejler (1105/9002), selv om der er plads på disken.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund for filer i ONLINE databaser med en MAXSIZE (> 0 og < 2 TB, der regnes som ubegrænset), når størrelse >= 90
|
||||
-- % af MAXSIZE.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 90 %; MAXSIZE på 2 TB eller mere regnes som ubegrænset (fast i koden).
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : FileMaxSizeRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
224
SQL Scripts/SQLI-DB-014.sql
Normal file
224
SQL Scripts/SQLI-DB-014.sql
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-014: Query Store indsamler ikke længere data
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-014
|
||||
-- Titel: Query Store indsamler ikke længere data
|
||||
-- Alvor: High ved ERROR; ellers Medium.
|
||||
-- Versioner: SQL Server 2016 og nyere (QueryStore).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om Query Store selv er gået over i READ_ONLY eller ERROR, så der ikke indsamles nye planer.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For ONLINE brugerdatabaser, der ikke er mirror/AG-sekundær, læses sys.database_query_store_options. Fund hvis
|
||||
-- desired_state_desc = READ_WRITE og actual_state_desc <> READ_WRITE. readonly_reason med bit 65536 betyder, at
|
||||
-- Query Store er fuld.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : QueryStoreStateRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
299
SQL Scripts/SQLI-DB-015.sql
Normal file
299
SQL Scripts/SQLI-DB-015.sql
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DB-015: tempdb har for få eller ulige store datafiler
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DB-015
|
||||
-- Titel: tempdb har for få eller ulige store datafiler
|
||||
-- Alvor: Medium for for få filer; Low for ulige store filer.
|
||||
-- Versioner: Alle. Ikke relevant på Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om tempdb har for få eller ulige store datafiler, hvilket giver PAGELATCH-contention på allokeringssider.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- tempdb's datafiler (type ROWS fra Files2005/Files2000, database_id 2) og cpu_count (ServerCollector). Anbefalet =
|
||||
-- min(8, logiske CPU'er). Fund 1: antal filer < anbefalet og < 4. Fund 2: mere end én fil, og størrelser eller
|
||||
-- autogrowth (MB/%) er ikke ens.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Op til 8 filer, én pr. logisk CPU; under 4 filer (fast i koden).
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- ServerCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ServerCollector.cs
|
||||
-- Medlemmer: ServerCollector.BuildSql(version), Db.StartTimeSql(version), ServerCollector.Sql2000
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:server)
|
||||
-- Delt script: SQL Scripts/_collectors/ServerCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Databases/DatabaseRules.cs : TempdbFilesRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt xp_msver (læser versionsoplysninger), SET-sessionsindstillinger. Intet ændrer
|
||||
-- data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ServerCollector: Starttidspunkt, logiske CPU'er, schedulers, NUMA-noder, fysisk hukommelse og virtualisering.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere
|
||||
-- Kilde: ServerCollector.BuildSql(2012+)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_kb / 1024,
|
||||
virtual_machine_type_desc
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og senere 2008 R2-builds
|
||||
-- Kilde: ServerCollector.BuildSql(2008 R2 SP1)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
virtual_machine_type_desc
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og 2008 R2 før SP1
|
||||
-- Kilde: ServerCollector.BuildSql(2008)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT sqlserver_start_time FROM sys.dm_os_sys_info),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
CAST(NULL AS nvarchar(60))
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005
|
||||
-- Kilde: ServerCollector.BuildSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.BuildSql(version)
|
||||
SELECT
|
||||
(SELECT create_date FROM sys.databases WHERE database_id = 2),
|
||||
cpu_count,
|
||||
(SELECT COUNT(*) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
(SELECT COUNT(DISTINCT parent_node_id) FROM sys.dm_os_schedulers WHERE status = N'VISIBLE ONLINE'),
|
||||
physical_memory_in_bytes / 1048576,
|
||||
CAST(NULL AS nvarchar(60))
|
||||
FROM sys.dm_os_sys_info
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: ServerCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): CPU og hukommelse
|
||||
-- Kilde: ServerCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ServerCollector.cs : ServerCollector.Sql2000
|
||||
EXEC master.dbo.xp_msver
|
||||
GO
|
||||
79
SQL Scripts/SQLI-DLK-001.sql
Normal file
79
SQL Scripts/SQLI-DLK-001.sql
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-DLK-001: Deadlocks
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-DLK-001
|
||||
-- Titel: Deadlocks
|
||||
-- Alvor: Medium; High fra 10 deadlocks siden sidste måling.
|
||||
-- Versioner: SQL Server 2008 og nyere (system_health). 2012+: event-filerne; 2008/2008 R2: ring buffer. SQL Server
|
||||
-- 2005: "tjek manuelt" (trace flag 1222).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om der er sket deadlocks siden forrige måling.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- xml_deadlock_report-hændelser fra system_health parses i C#. Første gang tages kun det seneste døgn med; derefter
|
||||
-- læses videre fra seneste fil og offset. Agentens egne deadlocks (program 'SQLInsight Pro') tælles ikke. Fund når
|
||||
-- der er nye deadlocks; de seneste 3 vises med processer.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen (High fra 10, fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DeadlockCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Concurrency/DeadlockCollector.cs
|
||||
-- Medlemmer: DeadlockCollector.BuildFileSql(lastFile: null, lastOffset: null), DeadlockCollector.RingBufferSql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:deadlocks)
|
||||
-- Delt script: SQL Scripts/_collectors/DeadlockCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Concurrency/ConcurrencyRules.cs : DeadlockRule.Evaluate
|
||||
--
|
||||
-- Read-only: IKKE STRENGT READ-ONLY. DeadlockCollector.BuildFileSql (SQL Server 2012+) opretter en midlertidig
|
||||
-- tabel i tempdb (SELECT ... INTO #system_health) og sletter den igen (DROP TABLE #system_health) i
|
||||
-- samme batch. Den er privat for sessionen; ingen brugerdata, indstillinger eller permanente objekter
|
||||
-- ændres, men det er en skrivning i tempdb. Ring buffer-varianten (2008/2008 R2) er read-only. Øvrigt:
|
||||
-- kun SELECT samt SET-sessionsindstillinger.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DeadlockCollector: Nye deadlock-grafer (xml_deadlock_report) fra den indbyggede system_health-session.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2012 og nyere (system_health-filer; første læsning)
|
||||
-- Kilde: DeadlockCollector.BuildFileSql
|
||||
-- Kode: src/SQLInsight.Collectors/Concurrency/DeadlockCollector.cs : DeadlockCollector.BuildFileSql(lastFile: null, lastOffset: null)
|
||||
SELECT object_name, file_name, file_offset,
|
||||
CASE WHEN object_name = N'xml_deadlock_report' THEN CAST(event_data AS nvarchar(max)) END AS event_data
|
||||
INTO #system_health
|
||||
FROM sys.fn_xe_file_target_read_file(N'system_health*.xel', NULL, NULL, NULL);
|
||||
|
||||
SELECT event_data FROM #system_health WHERE event_data IS NOT NULL;
|
||||
SELECT TOP (1) file_name, file_offset FROM #system_health ORDER BY file_name DESC, file_offset DESC;
|
||||
DROP TABLE #system_health;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 – 2008 R2, og når event-filerne ikke kan læses
|
||||
-- Kilde: DeadlockCollector.RingBufferSql
|
||||
-- Kode: src/SQLInsight.Collectors/Concurrency/DeadlockCollector.cs : DeadlockCollector.RingBufferSql
|
||||
SELECT CAST(t.target_data AS nvarchar(max))
|
||||
FROM sys.dm_xe_session_targets t
|
||||
JOIN sys.dm_xe_sessions s ON s.address = t.event_session_address
|
||||
WHERE s.name = N'system_health' AND t.target_name = N'ring_buffer'
|
||||
GO
|
||||
161
SQL Scripts/SQLI-IDX-001.sql
Normal file
161
SQL Scripts/SQLI-IDX-001.sql
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-IDX-001: Manglende index med stor effekt
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-IDX-001
|
||||
-- Titel: Manglende index med stor effekt
|
||||
-- Alvor: Medium hvis forbedringsmålet er mindst 1.000.000; ellers Low.
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om optimizeren gentagne gange har ønsket et index med stor effekt - vurderet kritisk mod de indexes, der allerede
|
||||
-- findes.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Forbedringsmål = avg_total_user_cost x (avg_user_impact / 100) x (user_seeks + user_scans). Fund for forslag med
|
||||
-- mål >= 50.000 og mindst 100 seeks + scans (højst 10, største først). C# sammenligner med tabellens eksisterende
|
||||
-- indexes: findes et nonclustered index med lighedskolonnerne forrest, foreslås det udvidet; mange indexes, mange
|
||||
-- skrivninger, brede INCLUDE og kort oppetid nævnes.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 50.000 (MinImprovementMeasure) og 100 brug (MinUses), fast i koden.
|
||||
--
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- IndexCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/IndexCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), IndexCollector.DatabasesSql, IndexCollector.MissingSql,
|
||||
-- IndexCollector.BuildIndexSql(database, filteredIndexes: true), IndexCollector.BuildIndexSql(database,
|
||||
-- filteredIndexes: false), IndexCollector.BuildStatisticsSql(database)
|
||||
-- Interval: 6 timer som standard (SQLInsight:CollectorIntervals:indexes)
|
||||
-- Delt script: SQL Scripts/_collectors/IndexCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Indexes/IndexRules.cs : MissingIndexRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- IndexCollector: Index-inventar med brug, manglende index-forslag og statistikker for hver læsbar brugerdatabase.
|
||||
-- Kun metadata og DMV'er; ingen tabeldata, ingen scanning.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt
|
||||
-- Kilde: IndexCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: IndexCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: IndexCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.DatabasesSql
|
||||
SELECT d.name FROM sys.databases d
|
||||
WHERE d.state = 0 AND d.database_id > 4 AND HAS_DBACCESS(d.name) = 1
|
||||
AND NOT EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: IndexCollector.MissingSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.MissingSql
|
||||
SELECT DB_NAME(d.database_id), d.statement, d.equality_columns, d.inequality_columns, d.included_columns,
|
||||
gs.user_seeks, gs.user_scans, gs.avg_total_user_cost, gs.avg_user_impact, gs.last_user_seek
|
||||
FROM sys.dm_db_missing_index_details d
|
||||
JOIN sys.dm_db_missing_index_groups g ON g.index_handle = d.index_handle
|
||||
JOIN sys.dm_db_missing_index_group_stats gs ON gs.group_handle = g.index_group_handle
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildIndexSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildIndexSql(database, filteredIndexes: true)
|
||||
SELECT s.name, o.name, i.index_id, i.name, i.type_desc, i.is_unique, i.is_primary_key, i.is_unique_constraint, i.is_disabled,
|
||||
i.filter_definition,
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0
|
||||
AND ic.key_ordinal > 0
|
||||
ORDER BY ic.key_ordinal
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1
|
||||
|
||||
ORDER BY c.name
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
ps.row_count, ps.used_pages,
|
||||
us.user_seeks, us.user_scans, us.user_lookups, us.user_updates,
|
||||
fw.forwarded
|
||||
FROM [msdb].sys.indexes i
|
||||
JOIN [msdb].sys.objects o ON o.object_id = i.object_id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
OUTER APPLY (SELECT SUM(p.row_count) AS row_count, SUM(p.used_page_count) AS used_pages
|
||||
FROM [msdb].sys.dm_db_partition_stats p WHERE p.object_id = i.object_id AND p.index_id = i.index_id) ps
|
||||
LEFT JOIN sys.dm_db_index_usage_stats us ON us.database_id = DB_ID(N'msdb') AND us.object_id = i.object_id AND us.index_id = i.index_id
|
||||
OUTER APPLY (SELECT SUM(os.forwarded_fetch_count) AS forwarded
|
||||
FROM sys.dm_db_index_operational_stats(DB_ID(N'msdb'), i.object_id, 0, NULL) os WHERE i.index_id = 0) fw;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildIndexSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildIndexSql(database, filteredIndexes: false)
|
||||
SELECT s.name, o.name, i.index_id, i.name, i.type_desc, i.is_unique, i.is_primary_key, i.is_unique_constraint, i.is_disabled,
|
||||
CAST(NULL AS nvarchar(max)),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0
|
||||
AND ic.key_ordinal > 0
|
||||
ORDER BY ic.key_ordinal
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1
|
||||
|
||||
ORDER BY c.name
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
ps.row_count, ps.used_pages,
|
||||
us.user_seeks, us.user_scans, us.user_lookups, us.user_updates,
|
||||
fw.forwarded
|
||||
FROM [msdb].sys.indexes i
|
||||
JOIN [msdb].sys.objects o ON o.object_id = i.object_id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
OUTER APPLY (SELECT SUM(p.row_count) AS row_count, SUM(p.used_page_count) AS used_pages
|
||||
FROM [msdb].sys.dm_db_partition_stats p WHERE p.object_id = i.object_id AND p.index_id = i.index_id) ps
|
||||
LEFT JOIN sys.dm_db_index_usage_stats us ON us.database_id = DB_ID(N'msdb') AND us.object_id = i.object_id AND us.index_id = i.index_id
|
||||
OUTER APPLY (SELECT SUM(os.forwarded_fetch_count) AS forwarded
|
||||
FROM sys.dm_db_index_operational_stats(DB_ID(N'msdb'), i.object_id, 0, NULL) os WHERE i.index_id = 0) fw;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildStatisticsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildStatisticsSql(database)
|
||||
SELECT s.name, o.name, si.name, STATS_DATE(si.id, si.indid),
|
||||
COALESCE((SELECT TOP 1 t.rowcnt FROM [msdb].sys.sysindexes t WHERE t.id = si.id AND t.indid IN (0, 1)), si.rowcnt), si.rowmodctr
|
||||
FROM [msdb].sys.sysindexes si
|
||||
JOIN [msdb].sys.objects o ON o.object_id = si.id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
WHERE si.indid > 0 AND si.indid < 255;
|
||||
GO
|
||||
160
SQL Scripts/SQLI-IDX-002.sql
Normal file
160
SQL Scripts/SQLI-IDX-002.sql
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-IDX-002: Ubrugt index koster ved hver skrivning
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-IDX-002
|
||||
-- Titel: Ubrugt index koster ved hver skrivning
|
||||
-- Alvor: Low; Medium fra 1 GB.
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om et nonclustered index vedligeholdes ved hver skrivning, men aldrig læses.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- sys.dm_db_index_usage_stats nulstilles ved genstart, så agenten følger brugen på tværs af genstarter
|
||||
-- (IndexUsageTracking). Fund for nonclustered, ikke-unikke, ikke-deaktiverede indexes (ikke PK/unik constraint),
|
||||
-- der er fulgt i mindst 7 dage, har 0 læsninger (seeks + scans + lookups), og har mindst 1.000 skrivninger eller
|
||||
-- fylder mindst 100 MB. Højst 10.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 7 dage (IndexText.MinUptimeForUsage), 1.000 skrivninger, 100 MB (fast i koden).
|
||||
--
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- IndexCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/IndexCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), IndexCollector.DatabasesSql, IndexCollector.MissingSql,
|
||||
-- IndexCollector.BuildIndexSql(database, filteredIndexes: true), IndexCollector.BuildIndexSql(database,
|
||||
-- filteredIndexes: false), IndexCollector.BuildStatisticsSql(database)
|
||||
-- Interval: 6 timer som standard (SQLInsight:CollectorIntervals:indexes)
|
||||
-- Delt script: SQL Scripts/_collectors/IndexCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Indexes/IndexRules.cs : UnusedIndexRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- IndexCollector: Index-inventar med brug, manglende index-forslag og statistikker for hver læsbar brugerdatabase.
|
||||
-- Kun metadata og DMV'er; ingen tabeldata, ingen scanning.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt
|
||||
-- Kilde: IndexCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: IndexCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: IndexCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.DatabasesSql
|
||||
SELECT d.name FROM sys.databases d
|
||||
WHERE d.state = 0 AND d.database_id > 4 AND HAS_DBACCESS(d.name) = 1
|
||||
AND NOT EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: IndexCollector.MissingSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.MissingSql
|
||||
SELECT DB_NAME(d.database_id), d.statement, d.equality_columns, d.inequality_columns, d.included_columns,
|
||||
gs.user_seeks, gs.user_scans, gs.avg_total_user_cost, gs.avg_user_impact, gs.last_user_seek
|
||||
FROM sys.dm_db_missing_index_details d
|
||||
JOIN sys.dm_db_missing_index_groups g ON g.index_handle = d.index_handle
|
||||
JOIN sys.dm_db_missing_index_group_stats gs ON gs.group_handle = g.index_group_handle
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildIndexSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildIndexSql(database, filteredIndexes: true)
|
||||
SELECT s.name, o.name, i.index_id, i.name, i.type_desc, i.is_unique, i.is_primary_key, i.is_unique_constraint, i.is_disabled,
|
||||
i.filter_definition,
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0
|
||||
AND ic.key_ordinal > 0
|
||||
ORDER BY ic.key_ordinal
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1
|
||||
|
||||
ORDER BY c.name
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
ps.row_count, ps.used_pages,
|
||||
us.user_seeks, us.user_scans, us.user_lookups, us.user_updates,
|
||||
fw.forwarded
|
||||
FROM [msdb].sys.indexes i
|
||||
JOIN [msdb].sys.objects o ON o.object_id = i.object_id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
OUTER APPLY (SELECT SUM(p.row_count) AS row_count, SUM(p.used_page_count) AS used_pages
|
||||
FROM [msdb].sys.dm_db_partition_stats p WHERE p.object_id = i.object_id AND p.index_id = i.index_id) ps
|
||||
LEFT JOIN sys.dm_db_index_usage_stats us ON us.database_id = DB_ID(N'msdb') AND us.object_id = i.object_id AND us.index_id = i.index_id
|
||||
OUTER APPLY (SELECT SUM(os.forwarded_fetch_count) AS forwarded
|
||||
FROM sys.dm_db_index_operational_stats(DB_ID(N'msdb'), i.object_id, 0, NULL) os WHERE i.index_id = 0) fw;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildIndexSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildIndexSql(database, filteredIndexes: false)
|
||||
SELECT s.name, o.name, i.index_id, i.name, i.type_desc, i.is_unique, i.is_primary_key, i.is_unique_constraint, i.is_disabled,
|
||||
CAST(NULL AS nvarchar(max)),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0
|
||||
AND ic.key_ordinal > 0
|
||||
ORDER BY ic.key_ordinal
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1
|
||||
|
||||
ORDER BY c.name
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
ps.row_count, ps.used_pages,
|
||||
us.user_seeks, us.user_scans, us.user_lookups, us.user_updates,
|
||||
fw.forwarded
|
||||
FROM [msdb].sys.indexes i
|
||||
JOIN [msdb].sys.objects o ON o.object_id = i.object_id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
OUTER APPLY (SELECT SUM(p.row_count) AS row_count, SUM(p.used_page_count) AS used_pages
|
||||
FROM [msdb].sys.dm_db_partition_stats p WHERE p.object_id = i.object_id AND p.index_id = i.index_id) ps
|
||||
LEFT JOIN sys.dm_db_index_usage_stats us ON us.database_id = DB_ID(N'msdb') AND us.object_id = i.object_id AND us.index_id = i.index_id
|
||||
OUTER APPLY (SELECT SUM(os.forwarded_fetch_count) AS forwarded
|
||||
FROM sys.dm_db_index_operational_stats(DB_ID(N'msdb'), i.object_id, 0, NULL) os WHERE i.index_id = 0) fw;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildStatisticsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildStatisticsSql(database)
|
||||
SELECT s.name, o.name, si.name, STATS_DATE(si.id, si.indid),
|
||||
COALESCE((SELECT TOP 1 t.rowcnt FROM [msdb].sys.sysindexes t WHERE t.id = si.id AND t.indid IN (0, 1)), si.rowcnt), si.rowmodctr
|
||||
FROM [msdb].sys.sysindexes si
|
||||
JOIN [msdb].sys.objects o ON o.object_id = si.id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
WHERE si.indid > 0 AND si.indid < 255;
|
||||
GO
|
||||
160
SQL Scripts/SQLI-IDX-003.sql
Normal file
160
SQL Scripts/SQLI-IDX-003.sql
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-IDX-003: Duplikeret eller overlappende index
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-IDX-003
|
||||
-- Titel: Duplikeret eller overlappende index
|
||||
-- Alvor: Medium for nøjagtige dubletter; Low for overlappende.
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om et index er overflødigt, fordi et andet index på samme tabel dækker det.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- I C#: et nonclustered index (ikke PK/unik constraint) er dækket af et andet, når filteret er ens, dets
|
||||
-- nøglekolonner er de første nøglekolonner i det andet (samme rækkefølge), et unikt index kun dækkes af et med
|
||||
-- præcis samme nøgler, og alle dets INCLUDE-kolonner findes i det andet (et clustered index dækker kun ved samme
|
||||
-- nøgler). Højst 10 fund.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- IndexCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/IndexCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), IndexCollector.DatabasesSql, IndexCollector.MissingSql,
|
||||
-- IndexCollector.BuildIndexSql(database, filteredIndexes: true), IndexCollector.BuildIndexSql(database,
|
||||
-- filteredIndexes: false), IndexCollector.BuildStatisticsSql(database)
|
||||
-- Interval: 6 timer som standard (SQLInsight:CollectorIntervals:indexes)
|
||||
-- Delt script: SQL Scripts/_collectors/IndexCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Indexes/IndexRules.cs : DuplicateIndexRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- IndexCollector: Index-inventar med brug, manglende index-forslag og statistikker for hver læsbar brugerdatabase.
|
||||
-- Kun metadata og DMV'er; ingen tabeldata, ingen scanning.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt
|
||||
-- Kilde: IndexCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: IndexCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: IndexCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.DatabasesSql
|
||||
SELECT d.name FROM sys.databases d
|
||||
WHERE d.state = 0 AND d.database_id > 4 AND HAS_DBACCESS(d.name) = 1
|
||||
AND NOT EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: IndexCollector.MissingSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.MissingSql
|
||||
SELECT DB_NAME(d.database_id), d.statement, d.equality_columns, d.inequality_columns, d.included_columns,
|
||||
gs.user_seeks, gs.user_scans, gs.avg_total_user_cost, gs.avg_user_impact, gs.last_user_seek
|
||||
FROM sys.dm_db_missing_index_details d
|
||||
JOIN sys.dm_db_missing_index_groups g ON g.index_handle = d.index_handle
|
||||
JOIN sys.dm_db_missing_index_group_stats gs ON gs.group_handle = g.index_group_handle
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildIndexSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildIndexSql(database, filteredIndexes: true)
|
||||
SELECT s.name, o.name, i.index_id, i.name, i.type_desc, i.is_unique, i.is_primary_key, i.is_unique_constraint, i.is_disabled,
|
||||
i.filter_definition,
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0
|
||||
AND ic.key_ordinal > 0
|
||||
ORDER BY ic.key_ordinal
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1
|
||||
|
||||
ORDER BY c.name
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
ps.row_count, ps.used_pages,
|
||||
us.user_seeks, us.user_scans, us.user_lookups, us.user_updates,
|
||||
fw.forwarded
|
||||
FROM [msdb].sys.indexes i
|
||||
JOIN [msdb].sys.objects o ON o.object_id = i.object_id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
OUTER APPLY (SELECT SUM(p.row_count) AS row_count, SUM(p.used_page_count) AS used_pages
|
||||
FROM [msdb].sys.dm_db_partition_stats p WHERE p.object_id = i.object_id AND p.index_id = i.index_id) ps
|
||||
LEFT JOIN sys.dm_db_index_usage_stats us ON us.database_id = DB_ID(N'msdb') AND us.object_id = i.object_id AND us.index_id = i.index_id
|
||||
OUTER APPLY (SELECT SUM(os.forwarded_fetch_count) AS forwarded
|
||||
FROM sys.dm_db_index_operational_stats(DB_ID(N'msdb'), i.object_id, 0, NULL) os WHERE i.index_id = 0) fw;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildIndexSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildIndexSql(database, filteredIndexes: false)
|
||||
SELECT s.name, o.name, i.index_id, i.name, i.type_desc, i.is_unique, i.is_primary_key, i.is_unique_constraint, i.is_disabled,
|
||||
CAST(NULL AS nvarchar(max)),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0
|
||||
AND ic.key_ordinal > 0
|
||||
ORDER BY ic.key_ordinal
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1
|
||||
|
||||
ORDER BY c.name
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
ps.row_count, ps.used_pages,
|
||||
us.user_seeks, us.user_scans, us.user_lookups, us.user_updates,
|
||||
fw.forwarded
|
||||
FROM [msdb].sys.indexes i
|
||||
JOIN [msdb].sys.objects o ON o.object_id = i.object_id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
OUTER APPLY (SELECT SUM(p.row_count) AS row_count, SUM(p.used_page_count) AS used_pages
|
||||
FROM [msdb].sys.dm_db_partition_stats p WHERE p.object_id = i.object_id AND p.index_id = i.index_id) ps
|
||||
LEFT JOIN sys.dm_db_index_usage_stats us ON us.database_id = DB_ID(N'msdb') AND us.object_id = i.object_id AND us.index_id = i.index_id
|
||||
OUTER APPLY (SELECT SUM(os.forwarded_fetch_count) AS forwarded
|
||||
FROM sys.dm_db_index_operational_stats(DB_ID(N'msdb'), i.object_id, 0, NULL) os WHERE i.index_id = 0) fw;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildStatisticsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildStatisticsSql(database)
|
||||
SELECT s.name, o.name, si.name, STATS_DATE(si.id, si.indid),
|
||||
COALESCE((SELECT TOP 1 t.rowcnt FROM [msdb].sys.sysindexes t WHERE t.id = si.id AND t.indid IN (0, 1)), si.rowcnt), si.rowmodctr
|
||||
FROM [msdb].sys.sysindexes si
|
||||
JOIN [msdb].sys.objects o ON o.object_id = si.id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
WHERE si.indid > 0 AND si.indid < 255;
|
||||
GO
|
||||
158
SQL Scripts/SQLI-IDX-004.sql
Normal file
158
SQL Scripts/SQLI-IDX-004.sql
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-IDX-004: Heap med mange forwarded records
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-IDX-004
|
||||
-- Titel: Heap med mange forwarded records
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en heap har mange forwarded records, så læsninger hopper rundt.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund for heaps (index_id 0) med mindst 10.000 rækker og mindst 10.000 forwarded_fetch_count
|
||||
-- (sys.dm_db_index_operational_stats, siden genstart). Højst 10, flest først.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 10.000 rækker og 10.000 forwarded fetches (fast i koden).
|
||||
--
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- IndexCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/IndexCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), IndexCollector.DatabasesSql, IndexCollector.MissingSql,
|
||||
-- IndexCollector.BuildIndexSql(database, filteredIndexes: true), IndexCollector.BuildIndexSql(database,
|
||||
-- filteredIndexes: false), IndexCollector.BuildStatisticsSql(database)
|
||||
-- Interval: 6 timer som standard (SQLInsight:CollectorIntervals:indexes)
|
||||
-- Delt script: SQL Scripts/_collectors/IndexCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Indexes/IndexRules.cs : ForwardedRecordsRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- IndexCollector: Index-inventar med brug, manglende index-forslag og statistikker for hver læsbar brugerdatabase.
|
||||
-- Kun metadata og DMV'er; ingen tabeldata, ingen scanning.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt
|
||||
-- Kilde: IndexCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: IndexCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: IndexCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.DatabasesSql
|
||||
SELECT d.name FROM sys.databases d
|
||||
WHERE d.state = 0 AND d.database_id > 4 AND HAS_DBACCESS(d.name) = 1
|
||||
AND NOT EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: IndexCollector.MissingSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.MissingSql
|
||||
SELECT DB_NAME(d.database_id), d.statement, d.equality_columns, d.inequality_columns, d.included_columns,
|
||||
gs.user_seeks, gs.user_scans, gs.avg_total_user_cost, gs.avg_user_impact, gs.last_user_seek
|
||||
FROM sys.dm_db_missing_index_details d
|
||||
JOIN sys.dm_db_missing_index_groups g ON g.index_handle = d.index_handle
|
||||
JOIN sys.dm_db_missing_index_group_stats gs ON gs.group_handle = g.index_group_handle
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildIndexSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildIndexSql(database, filteredIndexes: true)
|
||||
SELECT s.name, o.name, i.index_id, i.name, i.type_desc, i.is_unique, i.is_primary_key, i.is_unique_constraint, i.is_disabled,
|
||||
i.filter_definition,
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0
|
||||
AND ic.key_ordinal > 0
|
||||
ORDER BY ic.key_ordinal
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1
|
||||
|
||||
ORDER BY c.name
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
ps.row_count, ps.used_pages,
|
||||
us.user_seeks, us.user_scans, us.user_lookups, us.user_updates,
|
||||
fw.forwarded
|
||||
FROM [msdb].sys.indexes i
|
||||
JOIN [msdb].sys.objects o ON o.object_id = i.object_id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
OUTER APPLY (SELECT SUM(p.row_count) AS row_count, SUM(p.used_page_count) AS used_pages
|
||||
FROM [msdb].sys.dm_db_partition_stats p WHERE p.object_id = i.object_id AND p.index_id = i.index_id) ps
|
||||
LEFT JOIN sys.dm_db_index_usage_stats us ON us.database_id = DB_ID(N'msdb') AND us.object_id = i.object_id AND us.index_id = i.index_id
|
||||
OUTER APPLY (SELECT SUM(os.forwarded_fetch_count) AS forwarded
|
||||
FROM sys.dm_db_index_operational_stats(DB_ID(N'msdb'), i.object_id, 0, NULL) os WHERE i.index_id = 0) fw;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildIndexSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildIndexSql(database, filteredIndexes: false)
|
||||
SELECT s.name, o.name, i.index_id, i.name, i.type_desc, i.is_unique, i.is_primary_key, i.is_unique_constraint, i.is_disabled,
|
||||
CAST(NULL AS nvarchar(max)),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0
|
||||
AND ic.key_ordinal > 0
|
||||
ORDER BY ic.key_ordinal
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1
|
||||
|
||||
ORDER BY c.name
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
ps.row_count, ps.used_pages,
|
||||
us.user_seeks, us.user_scans, us.user_lookups, us.user_updates,
|
||||
fw.forwarded
|
||||
FROM [msdb].sys.indexes i
|
||||
JOIN [msdb].sys.objects o ON o.object_id = i.object_id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
OUTER APPLY (SELECT SUM(p.row_count) AS row_count, SUM(p.used_page_count) AS used_pages
|
||||
FROM [msdb].sys.dm_db_partition_stats p WHERE p.object_id = i.object_id AND p.index_id = i.index_id) ps
|
||||
LEFT JOIN sys.dm_db_index_usage_stats us ON us.database_id = DB_ID(N'msdb') AND us.object_id = i.object_id AND us.index_id = i.index_id
|
||||
OUTER APPLY (SELECT SUM(os.forwarded_fetch_count) AS forwarded
|
||||
FROM sys.dm_db_index_operational_stats(DB_ID(N'msdb'), i.object_id, 0, NULL) os WHERE i.index_id = 0) fw;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildStatisticsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildStatisticsSql(database)
|
||||
SELECT s.name, o.name, si.name, STATS_DATE(si.id, si.indid),
|
||||
COALESCE((SELECT TOP 1 t.rowcnt FROM [msdb].sys.sysindexes t WHERE t.id = si.id AND t.indid IN (0, 1)), si.rowcnt), si.rowmodctr
|
||||
FROM [msdb].sys.sysindexes si
|
||||
JOIN [msdb].sys.objects o ON o.object_id = si.id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
WHERE si.indid > 0 AND si.indid < 255;
|
||||
GO
|
||||
92
SQL Scripts/SQLI-IO-001.sql
Normal file
92
SQL Scripts/SQLI-IO-001.sql
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-IO-001: Høj læselatens på drev med datafiler
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-IO-001
|
||||
-- Titel: Høj læselatens på drev med datafiler
|
||||
-- Alvor: Medium; High fra 50 ms.
|
||||
-- Versioner: SQL Server 2005 og nyere (drev/mount point fra sys.dm_os_volume_stats fra 2008 R2 SP1; før det udledt
|
||||
-- af filstien).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om læsninger fra datafilerne på et drev er langsomme.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Forskellen mellem to målinger af sys.dm_io_virtual_file_stats (nulstilles ved genstart). Datafiler (ROWS)
|
||||
-- grupperes pr. drev: fund pr. drev, hvis der er mindst 1.000 læsninger i intervallet og gennemsnittet
|
||||
-- (io_stall_read_ms / num_of_reads) er mindst 20 ms. De tre langsomste filer står i målingerne.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- >= 1.000 læsninger; >= 20 ms; High fra 50 ms (fast i koden).
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- FileIoCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/FileIoCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), FileIoCollector.SqlWithVolumes, FileIoCollector.Sql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:file-io)
|
||||
-- Delt script: SQL Scripts/_collectors/FileIoCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/ResourceRules.cs : DataFileReadLatencyRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- FileIoCollector: Kumulativ I/O og I/O-ventetid pr. data- og logfil, med drev/mount point. Reglerne bruger
|
||||
-- forskellen mellem to målinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt
|
||||
-- Kilde: FileIoCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: FileIoCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og nyere (med drev/mount point)
|
||||
-- Kilde: FileIoCollector.SqlWithVolumes
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/FileIoCollector.cs : FileIoCollector.SqlWithVolumes
|
||||
SELECT DB_NAME(vfs.database_id), vfs.file_id, mf.type_desc, mf.physical_name,
|
||||
vfs.num_of_reads, vfs.num_of_bytes_read, vfs.io_stall_read_ms,
|
||||
vfs.num_of_writes, vfs.num_of_bytes_written, vfs.io_stall_write_ms,
|
||||
vs.volume_mount_point
|
||||
FROM sys.dm_io_virtual_file_stats(NULL, NULL) vfs
|
||||
JOIN sys.master_files mf ON mf.database_id = vfs.database_id AND mf.file_id = vfs.file_id
|
||||
OUTER APPLY sys.dm_os_volume_stats(vfs.database_id, vfs.file_id) vs
|
||||
WHERE mf.type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2 RTM
|
||||
-- Kilde: FileIoCollector.Sql
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/FileIoCollector.cs : FileIoCollector.Sql
|
||||
SELECT DB_NAME(vfs.database_id), vfs.file_id, mf.type_desc, mf.physical_name,
|
||||
vfs.num_of_reads, vfs.num_of_bytes_read, vfs.io_stall_read_ms,
|
||||
vfs.num_of_writes, vfs.num_of_bytes_written, vfs.io_stall_write_ms,
|
||||
CAST(NULL AS nvarchar(260))
|
||||
FROM sys.dm_io_virtual_file_stats(NULL, NULL) vfs
|
||||
JOIN sys.master_files mf ON mf.database_id = vfs.database_id AND mf.file_id = vfs.file_id
|
||||
WHERE mf.type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
90
SQL Scripts/SQLI-IO-002.sql
Normal file
90
SQL Scripts/SQLI-IO-002.sql
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-IO-002: Høj skrivelatens på drev med logfiler
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-IO-002
|
||||
-- Titel: Høj skrivelatens på drev med logfiler
|
||||
-- Alvor: Medium; High fra 15 ms.
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om skrivninger til logfilerne på et drev er langsomme, hvilket forsinker alle commits.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Forskellen mellem to målinger. Logfiler (LOG) grupperes pr. drev: fund pr. drev, hvis der er mindst 1.000
|
||||
-- skrivninger i intervallet og gennemsnittet (io_stall_write_ms / num_of_writes) er mindst 5 ms.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- >= 1.000 skrivninger; >= 5 ms; High fra 15 ms (fast i koden).
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- FileIoCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/FileIoCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), FileIoCollector.SqlWithVolumes, FileIoCollector.Sql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:file-io)
|
||||
-- Delt script: SQL Scripts/_collectors/FileIoCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/ResourceRules.cs : LogFileWriteLatencyRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- FileIoCollector: Kumulativ I/O og I/O-ventetid pr. data- og logfil, med drev/mount point. Reglerne bruger
|
||||
-- forskellen mellem to målinger.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt
|
||||
-- Kilde: FileIoCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: FileIoCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og nyere (med drev/mount point)
|
||||
-- Kilde: FileIoCollector.SqlWithVolumes
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/FileIoCollector.cs : FileIoCollector.SqlWithVolumes
|
||||
SELECT DB_NAME(vfs.database_id), vfs.file_id, mf.type_desc, mf.physical_name,
|
||||
vfs.num_of_reads, vfs.num_of_bytes_read, vfs.io_stall_read_ms,
|
||||
vfs.num_of_writes, vfs.num_of_bytes_written, vfs.io_stall_write_ms,
|
||||
vs.volume_mount_point
|
||||
FROM sys.dm_io_virtual_file_stats(NULL, NULL) vfs
|
||||
JOIN sys.master_files mf ON mf.database_id = vfs.database_id AND mf.file_id = vfs.file_id
|
||||
OUTER APPLY sys.dm_os_volume_stats(vfs.database_id, vfs.file_id) vs
|
||||
WHERE mf.type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2 RTM
|
||||
-- Kilde: FileIoCollector.Sql
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/FileIoCollector.cs : FileIoCollector.Sql
|
||||
SELECT DB_NAME(vfs.database_id), vfs.file_id, mf.type_desc, mf.physical_name,
|
||||
vfs.num_of_reads, vfs.num_of_bytes_read, vfs.io_stall_read_ms,
|
||||
vfs.num_of_writes, vfs.num_of_bytes_written, vfs.io_stall_write_ms,
|
||||
CAST(NULL AS nvarchar(260))
|
||||
FROM sys.dm_io_virtual_file_stats(NULL, NULL) vfs
|
||||
JOIN sys.master_files mf ON mf.database_id = vfs.database_id AND mf.file_id = vfs.file_id
|
||||
WHERE mf.type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
76
SQL Scripts/SQLI-JOB-001.sql
Normal file
76
SQL Scripts/SQLI-JOB-001.sql
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-JOB-001: SQL Agent-job fejler
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-JOB-001
|
||||
-- Titel: SQL Agent-job fejler
|
||||
-- Alvor: High hvis jobnavnet indeholder backup, checkdb, integrity eller dbcc; ellers Medium.
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om et aktivt SQL Agent-job fejlede ved seneste kørsel.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund pr. job med enabled = 1, hvor seneste job-udfald (sysjobhistory, step_id = 0, højeste instance_id) har
|
||||
-- run_status = 0 (fejlet). Seneste fejlende trin og dets besked samt antal fejl siden i går vises som målinger.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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+
|
||||
-- USE msdb; GRANT SELECT ON dbo.sysjobs TO [agent]; GRANT SELECT ON dbo.sysjobhistory TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AgentJobCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/AgentJobCollector.cs
|
||||
-- Medlemmer: AgentJobCollector.RunningSql, AgentJobCollector.JobsSql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:agent-jobs)
|
||||
-- Delt script: SQL Scripts/_collectors/AgentJobCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Availability/AvailabilityRules.cs : FailedJobRule.Evaluate
|
||||
--
|
||||
-- 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 (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AgentJobCollector: SQL Agent-jobs fra msdb: aktiv, seneste udfald, seneste fejlende trin og antal fejl det seneste
|
||||
-- døgn, og om SQL Server Agent kører.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: AgentJobCollector.RunningSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AgentJobCollector.cs : AgentJobCollector.RunningSql
|
||||
SELECT COUNT(*) FROM sys.dm_exec_sessions WHERE program_name LIKE N'SQLAgent - %'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: AgentJobCollector.JobsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AgentJobCollector.cs : AgentJobCollector.JobsSql
|
||||
DECLARE @since int;
|
||||
SET @since = CONVERT(int, CONVERT(char(8), DATEADD(day, -1, GETDATE()), 112));
|
||||
SELECT j.name, j.enabled, last_run.run_status, last_run.run_date, last_run.run_time,
|
||||
failed_step.step_name, LEFT(failed_step.message, 2000), failures.n
|
||||
FROM msdb.dbo.sysjobs j
|
||||
OUTER APPLY (SELECT TOP (1) h.run_status, h.run_date, h.run_time FROM msdb.dbo.sysjobhistory h
|
||||
WHERE h.job_id = j.job_id AND h.step_id = 0 ORDER BY h.instance_id DESC) last_run
|
||||
OUTER APPLY (SELECT TOP (1) h.step_name, h.message FROM msdb.dbo.sysjobhistory h
|
||||
WHERE h.job_id = j.job_id AND h.step_id > 0 AND h.run_status = 0 ORDER BY h.instance_id DESC) failed_step
|
||||
OUTER APPLY (SELECT COUNT(*) AS n FROM msdb.dbo.sysjobhistory h
|
||||
WHERE h.job_id = j.job_id AND h.step_id = 0 AND h.run_status = 0 AND h.run_date >= @since) failures
|
||||
GO
|
||||
101
SQL Scripts/SQLI-JOB-002.sql
Normal file
101
SQL Scripts/SQLI-JOB-002.sql
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-JOB-002: SQL Server Agent kører ikke
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-JOB-002
|
||||
-- Titel: SQL Server Agent kører ikke
|
||||
-- Alvor: High når der er aktive jobs; ellers Low.
|
||||
-- Versioner: SQL Server 2005 og nyere. Bestået på Express (EngineEdition fra InstanceProbe), som ikke har SQL
|
||||
-- Server Agent.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om SQL Server Agent ikke kører, så ingen planlagte jobs (backups!) bliver udført.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Agenten regnes som kørende, hvis der findes mindst én session med program_name LIKE 'SQLAgent - %'. Fund hvis
|
||||
-- ingen findes, og udgaven ikke er Express.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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+
|
||||
-- USE msdb; GRANT SELECT ON dbo.sysjobs TO [agent]; GRANT SELECT ON dbo.sysjobhistory TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AgentJobCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/AgentJobCollector.cs
|
||||
-- Medlemmer: AgentJobCollector.RunningSql, AgentJobCollector.JobsSql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:agent-jobs)
|
||||
-- Delt script: SQL Scripts/_collectors/AgentJobCollector.sql
|
||||
-- InstanceProbe
|
||||
-- Fil: src/SQLInsight.Connectivity/InstanceProbe.cs
|
||||
-- Medlemmer: InstanceProbe.Query
|
||||
-- Interval: én gang, når agenten forbinder til instansen
|
||||
-- Delt script: SQL Scripts/_collectors/InstanceProbe.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Availability/AvailabilityRules.cs : AgentStoppedRule.Evaluate
|
||||
--
|
||||
-- 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 (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AgentJobCollector: SQL Agent-jobs fra msdb: aktiv, seneste udfald, seneste fejlende trin og antal fejl det seneste
|
||||
-- døgn, og om SQL Server Agent kører.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: AgentJobCollector.RunningSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AgentJobCollector.cs : AgentJobCollector.RunningSql
|
||||
SELECT COUNT(*) FROM sys.dm_exec_sessions WHERE program_name LIKE N'SQLAgent - %'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: AgentJobCollector.JobsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/AgentJobCollector.cs : AgentJobCollector.JobsSql
|
||||
DECLARE @since int;
|
||||
SET @since = CONVERT(int, CONVERT(char(8), DATEADD(day, -1, GETDATE()), 112));
|
||||
SELECT j.name, j.enabled, last_run.run_status, last_run.run_date, last_run.run_time,
|
||||
failed_step.step_name, LEFT(failed_step.message, 2000), failures.n
|
||||
FROM msdb.dbo.sysjobs j
|
||||
OUTER APPLY (SELECT TOP (1) h.run_status, h.run_date, h.run_time FROM msdb.dbo.sysjobhistory h
|
||||
WHERE h.job_id = j.job_id AND h.step_id = 0 ORDER BY h.instance_id DESC) last_run
|
||||
OUTER APPLY (SELECT TOP (1) h.step_name, h.message FROM msdb.dbo.sysjobhistory h
|
||||
WHERE h.job_id = j.job_id AND h.step_id > 0 AND h.run_status = 0 ORDER BY h.instance_id DESC) failed_step
|
||||
OUTER APPLY (SELECT COUNT(*) AS n FROM msdb.dbo.sysjobhistory h
|
||||
WHERE h.job_id = j.job_id AND h.step_id = 0 AND h.run_status = 0 AND h.run_date >= @since) failures
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- InstanceProbe: Registrering af instansen: version, udgave, cluster og Always On. Køres, når agenten forbinder, og
|
||||
-- bestemmer hvilke varianter og regler der bruges.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner (SQL Server 2000 og nyere)
|
||||
-- Kilde: InstanceProbe.Query
|
||||
-- Kode: src/SQLInsight.Connectivity/InstanceProbe.cs : InstanceProbe.Query
|
||||
SELECT
|
||||
CAST(SERVERPROPERTY('ServerName') AS nvarchar(256)),
|
||||
CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductUpdateLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('Edition') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('EngineEdition') AS int),
|
||||
CAST(SERVERPROPERTY('IsClustered') AS int),
|
||||
CAST(SERVERPROPERTY('IsHadrEnabled') AS int)
|
||||
GO
|
||||
118
SQL Scripts/SQLI-LOG-001.sql
Normal file
118
SQL Scripts/SQLI-LOG-001.sql
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-LOG-001: SQL Server har læst beskadigede sider (fejl 823/824/825)
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-LOG-001
|
||||
-- Titel: SQL Server har læst beskadigede sider (fejl 823/824/825)
|
||||
-- Alvor: Critical for 823/824; High for 825.
|
||||
-- Versioner: SQL Server 2005 og nyere. Virker med alle tre kilder (fejllog, default trace, exception ring buffer).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om SQL Server har læst beskadigede sider (fejl 823, 824) eller måtte læse en side igen for at få den (825).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fejlloggen læses fra forrige måling (første gang den seneste time) fra den bedste kilde, agentens rettigheder
|
||||
-- giver: fejlloggen (securityadmin), default trace (ALTER TRACE) eller exception ring buffer (VIEW SERVER STATE).
|
||||
-- Fejl grupperes pr. fejlnummer; et fund pr. fejlnummer 823/824/825 set inden for de seneste 24 timer.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Fundet holdes åbent 24 timer efter seneste forekomst (ErrorLogAnalysis.RecentWindow, fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- Valgfrit: GRANT ALTER TRACE TO [agent]; -- default trace (udkommenteret i grant-least-privilege.sql; uden den bruges næste kilde)
|
||||
-- Valgfrit: ALTER SERVER ROLE [securityadmin] ADD MEMBER [agent]; -- xp_readerrorlog; gives IKKE som standard
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ErrorLogCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs
|
||||
-- Medlemmer: ErrorLogCollector.CanReadErrorLogSql, ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal),
|
||||
-- PrivilegeCollector.DefaultTracePathSql, ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal),
|
||||
-- ErrorLogCollector.RingBufferSql, ErrorLogCollector.ConnectivitySql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:error-log)
|
||||
-- Delt script: SQL Scripts/_collectors/ErrorLogCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Instance/ErrorLogRules.cs : CorruptionErrorRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt xp_readerrorlog (læser fejlloggen), sys.fn_trace_gettable (læser default trace),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ErrorLogCollector: SQL Server-fejlloggen siden forrige måling fra den bedste kilde, agentens rettigheder giver: 1)
|
||||
-- fejlloggen (xp_readerrorlog, kræver securityadmin), 2) default trace (kræver ALTER TRACE), 3) exception- og
|
||||
-- connectivity ring buffer (kun fejlnumre).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ErrorLogCollector.CanReadErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.CanReadErrorLogSql
|
||||
SELECT CASE WHEN IS_SRVROLEMEMBER(N'securityadmin') = 1 OR IS_SRVROLEMEMBER(N'sysadmin') = 1 THEN 1 ELSE 0 END,
|
||||
DATEDIFF(minute, GETUTCDATE(), GETDATE()), GETUTCDATE()
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 1: fejlloggen (når agenten er securityadmin)
|
||||
-- Kilde: ErrorLogCollector.BuildErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal)
|
||||
-- Agenten indsætter tidspunktet for forrige måling og nu + 1 minut (serverens lokale tid) som literaler, fx
|
||||
-- '2026-10-02T09:00:00'. Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fra nvarchar(19);
|
||||
DECLARE @til nvarchar(19);
|
||||
SET @fra = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SET @til = CONVERT(nvarchar(19), DATEADD(minute, 1, GETDATE()), 126);
|
||||
EXEC master.dbo.xp_readerrorlog 0, 1, NULL, NULL, @fra, @til
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.DefaultTracePathSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.DefaultTracePathSql
|
||||
SELECT path, DATEDIFF(minute, GETUTCDATE(), GETDATE()) FROM sys.traces WHERE is_default = 1
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.BuildDefaultTraceSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal)
|
||||
-- Agenten indsætter filargumenterne som literaler: første gang og efter rollover mappen + log.trc med DEFAULT (alle
|
||||
-- rollover-filer), ellers den aktuelle fil med 1 (kun den fil), samt tidspunktet for forrige måling (lokal tid).
|
||||
-- Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fil nvarchar(260);
|
||||
DECLARE @siden nvarchar(19);
|
||||
SELECT @fil = LEFT(path, LEN(path) - CHARINDEX(N'\', REVERSE(path)) + 1) + N'log.trc' FROM sys.traces WHERE is_default = 1;
|
||||
SET @siden = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SELECT StartTime, EventClass, Error, Severity, CAST(TextData AS nvarchar(2000))
|
||||
FROM sys.fn_trace_gettable(@fil, DEFAULT)
|
||||
WHERE EventClass IN (20, 22) AND StartTime > @siden
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 3: exception ring buffer (kun VIEW SERVER STATE)
|
||||
-- Kilde: ErrorLogCollector.RingBufferSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.RingBufferSql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//Exception/Error)[1]', 'int'), rb.x.value('(//Exception/Severity)[1]', 'int')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers WHERE ring_buffer_type = N'RING_BUFFER_EXCEPTION') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere, kilde 3: mislykkede logins fra connectivity ring buffer
|
||||
-- Kilde: ErrorLogCollector.ConnectivitySql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.ConnectivitySql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//SniConsumerError)[1]', 'int'), rb.x.value('(//State)[1]', 'int'), rb.x.value('(//RemoteHost)[1]', 'nvarchar(128)')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers
|
||||
WHERE ring_buffer_type = N'RING_BUFFER_CONNECTIVITY' AND record LIKE N'%<SniConsumerError>18456</SniConsumerError>%') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
118
SQL Scripts/SQLI-LOG-002.sql
Normal file
118
SQL Scripts/SQLI-LOG-002.sql
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-LOG-002: I/O-forespørgsler, der tager over 15 sekunder (fejl 833)
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-LOG-002
|
||||
-- Titel: I/O-forespørgsler, der tager over 15 sekunder (fejl 833)
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver at fejlloggen selv kan læses (xp_readerrorlog, serverrollen
|
||||
-- securityadmin): fejl 833 står hverken i default trace eller ring buffer, så ellers er reglen "ikke
|
||||
-- målbar".
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om storage har brugt over 15 sekunder på I/O-forespørgsler (fejl 833).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Som SQLI-LOG-001, men kun med kilden "fejlloggen": et fund, når fejl 833 er set inden for de seneste 24 timer.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 24 timer (ErrorLogAnalysis.RecentWindow).
|
||||
--
|
||||
-- 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+
|
||||
-- Valgfrit: GRANT ALTER TRACE TO [agent]; -- default trace (udkommenteret i grant-least-privilege.sql; uden den bruges næste kilde)
|
||||
-- Valgfrit: ALTER SERVER ROLE [securityadmin] ADD MEMBER [agent]; -- xp_readerrorlog; gives IKKE som standard
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ErrorLogCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs
|
||||
-- Medlemmer: ErrorLogCollector.CanReadErrorLogSql, ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal),
|
||||
-- PrivilegeCollector.DefaultTracePathSql, ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal),
|
||||
-- ErrorLogCollector.RingBufferSql, ErrorLogCollector.ConnectivitySql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:error-log)
|
||||
-- Delt script: SQL Scripts/_collectors/ErrorLogCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Instance/ErrorLogRules.cs : SlowIoErrorRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt xp_readerrorlog (læser fejlloggen), sys.fn_trace_gettable (læser default trace),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ErrorLogCollector: SQL Server-fejlloggen siden forrige måling fra den bedste kilde, agentens rettigheder giver: 1)
|
||||
-- fejlloggen (xp_readerrorlog, kræver securityadmin), 2) default trace (kræver ALTER TRACE), 3) exception- og
|
||||
-- connectivity ring buffer (kun fejlnumre).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ErrorLogCollector.CanReadErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.CanReadErrorLogSql
|
||||
SELECT CASE WHEN IS_SRVROLEMEMBER(N'securityadmin') = 1 OR IS_SRVROLEMEMBER(N'sysadmin') = 1 THEN 1 ELSE 0 END,
|
||||
DATEDIFF(minute, GETUTCDATE(), GETDATE()), GETUTCDATE()
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 1: fejlloggen (når agenten er securityadmin)
|
||||
-- Kilde: ErrorLogCollector.BuildErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal)
|
||||
-- Agenten indsætter tidspunktet for forrige måling og nu + 1 minut (serverens lokale tid) som literaler, fx
|
||||
-- '2026-10-02T09:00:00'. Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fra nvarchar(19);
|
||||
DECLARE @til nvarchar(19);
|
||||
SET @fra = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SET @til = CONVERT(nvarchar(19), DATEADD(minute, 1, GETDATE()), 126);
|
||||
EXEC master.dbo.xp_readerrorlog 0, 1, NULL, NULL, @fra, @til
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.DefaultTracePathSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.DefaultTracePathSql
|
||||
SELECT path, DATEDIFF(minute, GETUTCDATE(), GETDATE()) FROM sys.traces WHERE is_default = 1
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.BuildDefaultTraceSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal)
|
||||
-- Agenten indsætter filargumenterne som literaler: første gang og efter rollover mappen + log.trc med DEFAULT (alle
|
||||
-- rollover-filer), ellers den aktuelle fil med 1 (kun den fil), samt tidspunktet for forrige måling (lokal tid).
|
||||
-- Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fil nvarchar(260);
|
||||
DECLARE @siden nvarchar(19);
|
||||
SELECT @fil = LEFT(path, LEN(path) - CHARINDEX(N'\', REVERSE(path)) + 1) + N'log.trc' FROM sys.traces WHERE is_default = 1;
|
||||
SET @siden = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SELECT StartTime, EventClass, Error, Severity, CAST(TextData AS nvarchar(2000))
|
||||
FROM sys.fn_trace_gettable(@fil, DEFAULT)
|
||||
WHERE EventClass IN (20, 22) AND StartTime > @siden
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 3: exception ring buffer (kun VIEW SERVER STATE)
|
||||
-- Kilde: ErrorLogCollector.RingBufferSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.RingBufferSql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//Exception/Error)[1]', 'int'), rb.x.value('(//Exception/Severity)[1]', 'int')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers WHERE ring_buffer_type = N'RING_BUFFER_EXCEPTION') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere, kilde 3: mislykkede logins fra connectivity ring buffer
|
||||
-- Kilde: ErrorLogCollector.ConnectivitySql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.ConnectivitySql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//SniConsumerError)[1]', 'int'), rb.x.value('(//State)[1]', 'int'), rb.x.value('(//RemoteHost)[1]', 'nvarchar(128)')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers
|
||||
WHERE ring_buffer_type = N'RING_BUFFER_CONNECTIVITY' AND record LIKE N'%<SniConsumerError>18456</SniConsumerError>%') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
117
SQL Scripts/SQLI-LOG-003.sql
Normal file
117
SQL Scripts/SQLI-LOG-003.sql
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-LOG-003: Alvorlige fejl i SQL Servers fejllog (severity 17 og derover)
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-LOG-003
|
||||
-- Titel: Alvorlige fejl i SQL Servers fejllog (severity 17 og derover)
|
||||
-- Alvor: High fra severity 20; ellers Medium.
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om fejlloggen indeholder alvorlige fejl (severity 17 og derover), som ikke er korruption, langsom I/O, mislykkede
|
||||
-- logins, stack dumps eller AG-fejl (de har egne regler).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fejl grupperes pr. fejlnummer; ét fund pr. fejlnummer med severity >= 17 set inden for de seneste 24 timer.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Severity >= 17; 24 timer.
|
||||
--
|
||||
-- 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+
|
||||
-- Valgfrit: GRANT ALTER TRACE TO [agent]; -- default trace (udkommenteret i grant-least-privilege.sql; uden den bruges næste kilde)
|
||||
-- Valgfrit: ALTER SERVER ROLE [securityadmin] ADD MEMBER [agent]; -- xp_readerrorlog; gives IKKE som standard
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ErrorLogCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs
|
||||
-- Medlemmer: ErrorLogCollector.CanReadErrorLogSql, ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal),
|
||||
-- PrivilegeCollector.DefaultTracePathSql, ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal),
|
||||
-- ErrorLogCollector.RingBufferSql, ErrorLogCollector.ConnectivitySql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:error-log)
|
||||
-- Delt script: SQL Scripts/_collectors/ErrorLogCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Instance/ErrorLogRules.cs : SevereErrorRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt xp_readerrorlog (læser fejlloggen), sys.fn_trace_gettable (læser default trace),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ErrorLogCollector: SQL Server-fejlloggen siden forrige måling fra den bedste kilde, agentens rettigheder giver: 1)
|
||||
-- fejlloggen (xp_readerrorlog, kræver securityadmin), 2) default trace (kræver ALTER TRACE), 3) exception- og
|
||||
-- connectivity ring buffer (kun fejlnumre).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ErrorLogCollector.CanReadErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.CanReadErrorLogSql
|
||||
SELECT CASE WHEN IS_SRVROLEMEMBER(N'securityadmin') = 1 OR IS_SRVROLEMEMBER(N'sysadmin') = 1 THEN 1 ELSE 0 END,
|
||||
DATEDIFF(minute, GETUTCDATE(), GETDATE()), GETUTCDATE()
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 1: fejlloggen (når agenten er securityadmin)
|
||||
-- Kilde: ErrorLogCollector.BuildErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal)
|
||||
-- Agenten indsætter tidspunktet for forrige måling og nu + 1 minut (serverens lokale tid) som literaler, fx
|
||||
-- '2026-10-02T09:00:00'. Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fra nvarchar(19);
|
||||
DECLARE @til nvarchar(19);
|
||||
SET @fra = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SET @til = CONVERT(nvarchar(19), DATEADD(minute, 1, GETDATE()), 126);
|
||||
EXEC master.dbo.xp_readerrorlog 0, 1, NULL, NULL, @fra, @til
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.DefaultTracePathSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.DefaultTracePathSql
|
||||
SELECT path, DATEDIFF(minute, GETUTCDATE(), GETDATE()) FROM sys.traces WHERE is_default = 1
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.BuildDefaultTraceSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal)
|
||||
-- Agenten indsætter filargumenterne som literaler: første gang og efter rollover mappen + log.trc med DEFAULT (alle
|
||||
-- rollover-filer), ellers den aktuelle fil med 1 (kun den fil), samt tidspunktet for forrige måling (lokal tid).
|
||||
-- Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fil nvarchar(260);
|
||||
DECLARE @siden nvarchar(19);
|
||||
SELECT @fil = LEFT(path, LEN(path) - CHARINDEX(N'\', REVERSE(path)) + 1) + N'log.trc' FROM sys.traces WHERE is_default = 1;
|
||||
SET @siden = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SELECT StartTime, EventClass, Error, Severity, CAST(TextData AS nvarchar(2000))
|
||||
FROM sys.fn_trace_gettable(@fil, DEFAULT)
|
||||
WHERE EventClass IN (20, 22) AND StartTime > @siden
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 3: exception ring buffer (kun VIEW SERVER STATE)
|
||||
-- Kilde: ErrorLogCollector.RingBufferSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.RingBufferSql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//Exception/Error)[1]', 'int'), rb.x.value('(//Exception/Severity)[1]', 'int')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers WHERE ring_buffer_type = N'RING_BUFFER_EXCEPTION') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere, kilde 3: mislykkede logins fra connectivity ring buffer
|
||||
-- Kilde: ErrorLogCollector.ConnectivitySql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.ConnectivitySql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//SniConsumerError)[1]', 'int'), rb.x.value('(//State)[1]', 'int'), rb.x.value('(//RemoteHost)[1]', 'nvarchar(128)')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers
|
||||
WHERE ring_buffer_type = N'RING_BUFFER_CONNECTIVITY' AND record LIKE N'%<SniConsumerError>18456</SniConsumerError>%') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
118
SQL Scripts/SQLI-LOG-004.sql
Normal file
118
SQL Scripts/SQLI-LOG-004.sql
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-LOG-004: Mange mislykkede logins
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-LOG-004
|
||||
-- Titel: Mange mislykkede logins
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere (fra ring buffer kun 2008+ via connectivity ring buffer).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om der er mange mislykkede logins (fejl 18456) på kort tid: forkert kodeord i en applikation eller et forsøg på
|
||||
-- at gætte kodeord.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Kun den seneste måling (ikke døgnets sum): fund hvis antallet af fejl 18456 siden forrige måling (normalt 5
|
||||
-- minutter) er mindst grænsen.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:ErrorLog:LoginFailureBurst, standard 20.
|
||||
--
|
||||
-- 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+
|
||||
-- Valgfrit: GRANT ALTER TRACE TO [agent]; -- default trace (udkommenteret i grant-least-privilege.sql; uden den bruges næste kilde)
|
||||
-- Valgfrit: ALTER SERVER ROLE [securityadmin] ADD MEMBER [agent]; -- xp_readerrorlog; gives IKKE som standard
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ErrorLogCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs
|
||||
-- Medlemmer: ErrorLogCollector.CanReadErrorLogSql, ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal),
|
||||
-- PrivilegeCollector.DefaultTracePathSql, ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal),
|
||||
-- ErrorLogCollector.RingBufferSql, ErrorLogCollector.ConnectivitySql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:error-log)
|
||||
-- Delt script: SQL Scripts/_collectors/ErrorLogCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Instance/ErrorLogRules.cs : LoginFailureBurstRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt xp_readerrorlog (læser fejlloggen), sys.fn_trace_gettable (læser default trace),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ErrorLogCollector: SQL Server-fejlloggen siden forrige måling fra den bedste kilde, agentens rettigheder giver: 1)
|
||||
-- fejlloggen (xp_readerrorlog, kræver securityadmin), 2) default trace (kræver ALTER TRACE), 3) exception- og
|
||||
-- connectivity ring buffer (kun fejlnumre).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ErrorLogCollector.CanReadErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.CanReadErrorLogSql
|
||||
SELECT CASE WHEN IS_SRVROLEMEMBER(N'securityadmin') = 1 OR IS_SRVROLEMEMBER(N'sysadmin') = 1 THEN 1 ELSE 0 END,
|
||||
DATEDIFF(minute, GETUTCDATE(), GETDATE()), GETUTCDATE()
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 1: fejlloggen (når agenten er securityadmin)
|
||||
-- Kilde: ErrorLogCollector.BuildErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal)
|
||||
-- Agenten indsætter tidspunktet for forrige måling og nu + 1 minut (serverens lokale tid) som literaler, fx
|
||||
-- '2026-10-02T09:00:00'. Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fra nvarchar(19);
|
||||
DECLARE @til nvarchar(19);
|
||||
SET @fra = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SET @til = CONVERT(nvarchar(19), DATEADD(minute, 1, GETDATE()), 126);
|
||||
EXEC master.dbo.xp_readerrorlog 0, 1, NULL, NULL, @fra, @til
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.DefaultTracePathSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.DefaultTracePathSql
|
||||
SELECT path, DATEDIFF(minute, GETUTCDATE(), GETDATE()) FROM sys.traces WHERE is_default = 1
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.BuildDefaultTraceSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal)
|
||||
-- Agenten indsætter filargumenterne som literaler: første gang og efter rollover mappen + log.trc med DEFAULT (alle
|
||||
-- rollover-filer), ellers den aktuelle fil med 1 (kun den fil), samt tidspunktet for forrige måling (lokal tid).
|
||||
-- Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fil nvarchar(260);
|
||||
DECLARE @siden nvarchar(19);
|
||||
SELECT @fil = LEFT(path, LEN(path) - CHARINDEX(N'\', REVERSE(path)) + 1) + N'log.trc' FROM sys.traces WHERE is_default = 1;
|
||||
SET @siden = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SELECT StartTime, EventClass, Error, Severity, CAST(TextData AS nvarchar(2000))
|
||||
FROM sys.fn_trace_gettable(@fil, DEFAULT)
|
||||
WHERE EventClass IN (20, 22) AND StartTime > @siden
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 3: exception ring buffer (kun VIEW SERVER STATE)
|
||||
-- Kilde: ErrorLogCollector.RingBufferSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.RingBufferSql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//Exception/Error)[1]', 'int'), rb.x.value('(//Exception/Severity)[1]', 'int')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers WHERE ring_buffer_type = N'RING_BUFFER_EXCEPTION') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere, kilde 3: mislykkede logins fra connectivity ring buffer
|
||||
-- Kilde: ErrorLogCollector.ConnectivitySql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.ConnectivitySql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//SniConsumerError)[1]', 'int'), rb.x.value('(//State)[1]', 'int'), rb.x.value('(//RemoteHost)[1]', 'nvarchar(128)')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers
|
||||
WHERE ring_buffer_type = N'RING_BUFFER_CONNECTIVITY' AND record LIKE N'%<SniConsumerError>18456</SniConsumerError>%') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
116
SQL Scripts/SQLI-LOG-005.sql
Normal file
116
SQL Scripts/SQLI-LOG-005.sql
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-LOG-005: SQL Server har lavet et stack dump
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-LOG-005
|
||||
-- Titel: SQL Server har lavet et stack dump
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2005 og nyere. Kræver at fejlloggen selv kan læses (securityadmin); ellers "ikke målbar".
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om SQL Server har lavet et stack dump (intern fejl, access violation, assertion).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fejl 17065, 17066, 17067, 17310 eller tekst med "Stack Dump" i fejlloggen inden for de seneste 24 timer.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 24 timer.
|
||||
--
|
||||
-- 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+
|
||||
-- Valgfrit: GRANT ALTER TRACE TO [agent]; -- default trace (udkommenteret i grant-least-privilege.sql; uden den bruges næste kilde)
|
||||
-- Valgfrit: ALTER SERVER ROLE [securityadmin] ADD MEMBER [agent]; -- xp_readerrorlog; gives IKKE som standard
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ErrorLogCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs
|
||||
-- Medlemmer: ErrorLogCollector.CanReadErrorLogSql, ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal),
|
||||
-- PrivilegeCollector.DefaultTracePathSql, ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal),
|
||||
-- ErrorLogCollector.RingBufferSql, ErrorLogCollector.ConnectivitySql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:error-log)
|
||||
-- Delt script: SQL Scripts/_collectors/ErrorLogCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Instance/ErrorLogRules.cs : StackDumpRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt xp_readerrorlog (læser fejlloggen), sys.fn_trace_gettable (læser default trace),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ErrorLogCollector: SQL Server-fejlloggen siden forrige måling fra den bedste kilde, agentens rettigheder giver: 1)
|
||||
-- fejlloggen (xp_readerrorlog, kræver securityadmin), 2) default trace (kræver ALTER TRACE), 3) exception- og
|
||||
-- connectivity ring buffer (kun fejlnumre).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ErrorLogCollector.CanReadErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.CanReadErrorLogSql
|
||||
SELECT CASE WHEN IS_SRVROLEMEMBER(N'securityadmin') = 1 OR IS_SRVROLEMEMBER(N'sysadmin') = 1 THEN 1 ELSE 0 END,
|
||||
DATEDIFF(minute, GETUTCDATE(), GETDATE()), GETUTCDATE()
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 1: fejlloggen (når agenten er securityadmin)
|
||||
-- Kilde: ErrorLogCollector.BuildErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal)
|
||||
-- Agenten indsætter tidspunktet for forrige måling og nu + 1 minut (serverens lokale tid) som literaler, fx
|
||||
-- '2026-10-02T09:00:00'. Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fra nvarchar(19);
|
||||
DECLARE @til nvarchar(19);
|
||||
SET @fra = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SET @til = CONVERT(nvarchar(19), DATEADD(minute, 1, GETDATE()), 126);
|
||||
EXEC master.dbo.xp_readerrorlog 0, 1, NULL, NULL, @fra, @til
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.DefaultTracePathSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.DefaultTracePathSql
|
||||
SELECT path, DATEDIFF(minute, GETUTCDATE(), GETDATE()) FROM sys.traces WHERE is_default = 1
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.BuildDefaultTraceSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal)
|
||||
-- Agenten indsætter filargumenterne som literaler: første gang og efter rollover mappen + log.trc med DEFAULT (alle
|
||||
-- rollover-filer), ellers den aktuelle fil med 1 (kun den fil), samt tidspunktet for forrige måling (lokal tid).
|
||||
-- Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fil nvarchar(260);
|
||||
DECLARE @siden nvarchar(19);
|
||||
SELECT @fil = LEFT(path, LEN(path) - CHARINDEX(N'\', REVERSE(path)) + 1) + N'log.trc' FROM sys.traces WHERE is_default = 1;
|
||||
SET @siden = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SELECT StartTime, EventClass, Error, Severity, CAST(TextData AS nvarchar(2000))
|
||||
FROM sys.fn_trace_gettable(@fil, DEFAULT)
|
||||
WHERE EventClass IN (20, 22) AND StartTime > @siden
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 3: exception ring buffer (kun VIEW SERVER STATE)
|
||||
-- Kilde: ErrorLogCollector.RingBufferSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.RingBufferSql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//Exception/Error)[1]', 'int'), rb.x.value('(//Exception/Severity)[1]', 'int')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers WHERE ring_buffer_type = N'RING_BUFFER_EXCEPTION') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere, kilde 3: mislykkede logins fra connectivity ring buffer
|
||||
-- Kilde: ErrorLogCollector.ConnectivitySql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.ConnectivitySql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//SniConsumerError)[1]', 'int'), rb.x.value('(//State)[1]', 'int'), rb.x.value('(//RemoteHost)[1]', 'nvarchar(128)')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers
|
||||
WHERE ring_buffer_type = N'RING_BUFFER_CONNECTIVITY' AND record LIKE N'%<SniConsumerError>18456</SniConsumerError>%') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
117
SQL Scripts/SQLI-LOG-006.sql
Normal file
117
SQL Scripts/SQLI-LOG-006.sql
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-LOG-006: Fejl i Always On availability groups
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-LOG-006
|
||||
-- Titel: Fejl i Always On availability groups
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2005 og nyere (relevant fra 2012).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om fejlloggen viser fejl fra Always On availability groups.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fejl 1480, 19406, 41131, 41142, 41143, 41144, 35201-35299, eller tekst med "availability group" og severity >= 16
|
||||
-- eller "failed", inden for de seneste 24 timer. Ét fund pr. fejlnummer.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 24 timer.
|
||||
--
|
||||
-- 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+
|
||||
-- Valgfrit: GRANT ALTER TRACE TO [agent]; -- default trace (udkommenteret i grant-least-privilege.sql; uden den bruges næste kilde)
|
||||
-- Valgfrit: ALTER SERVER ROLE [securityadmin] ADD MEMBER [agent]; -- xp_readerrorlog; gives IKKE som standard
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ErrorLogCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs
|
||||
-- Medlemmer: ErrorLogCollector.CanReadErrorLogSql, ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal),
|
||||
-- PrivilegeCollector.DefaultTracePathSql, ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal),
|
||||
-- ErrorLogCollector.RingBufferSql, ErrorLogCollector.ConnectivitySql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:error-log)
|
||||
-- Delt script: SQL Scripts/_collectors/ErrorLogCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Instance/ErrorLogRules.cs : AvailabilityGroupErrorRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt xp_readerrorlog (læser fejlloggen), sys.fn_trace_gettable (læser default trace),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ErrorLogCollector: SQL Server-fejlloggen siden forrige måling fra den bedste kilde, agentens rettigheder giver: 1)
|
||||
-- fejlloggen (xp_readerrorlog, kræver securityadmin), 2) default trace (kræver ALTER TRACE), 3) exception- og
|
||||
-- connectivity ring buffer (kun fejlnumre).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ErrorLogCollector.CanReadErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.CanReadErrorLogSql
|
||||
SELECT CASE WHEN IS_SRVROLEMEMBER(N'securityadmin') = 1 OR IS_SRVROLEMEMBER(N'sysadmin') = 1 THEN 1 ELSE 0 END,
|
||||
DATEDIFF(minute, GETUTCDATE(), GETDATE()), GETUTCDATE()
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 1: fejlloggen (når agenten er securityadmin)
|
||||
-- Kilde: ErrorLogCollector.BuildErrorLogSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal)
|
||||
-- Agenten indsætter tidspunktet for forrige måling og nu + 1 minut (serverens lokale tid) som literaler, fx
|
||||
-- '2026-10-02T09:00:00'. Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fra nvarchar(19);
|
||||
DECLARE @til nvarchar(19);
|
||||
SET @fra = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SET @til = CONVERT(nvarchar(19), DATEADD(minute, 1, GETDATE()), 126);
|
||||
EXEC master.dbo.xp_readerrorlog 0, 1, NULL, NULL, @fra, @til
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.DefaultTracePathSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.DefaultTracePathSql
|
||||
SELECT path, DATEDIFF(minute, GETUTCDATE(), GETDATE()) FROM sys.traces WHERE is_default = 1
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)
|
||||
-- Kilde: ErrorLogCollector.BuildDefaultTraceSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal)
|
||||
-- Agenten indsætter filargumenterne som literaler: første gang og efter rollover mappen + log.trc med DEFAULT (alle
|
||||
-- rollover-filer), ellers den aktuelle fil med 1 (kun den fil), samt tidspunktet for forrige måling (lokal tid).
|
||||
-- Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fil nvarchar(260);
|
||||
DECLARE @siden nvarchar(19);
|
||||
SELECT @fil = LEFT(path, LEN(path) - CHARINDEX(N'\', REVERSE(path)) + 1) + N'log.trc' FROM sys.traces WHERE is_default = 1;
|
||||
SET @siden = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SELECT StartTime, EventClass, Error, Severity, CAST(TextData AS nvarchar(2000))
|
||||
FROM sys.fn_trace_gettable(@fil, DEFAULT)
|
||||
WHERE EventClass IN (20, 22) AND StartTime > @siden
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kilde 3: exception ring buffer (kun VIEW SERVER STATE)
|
||||
-- Kilde: ErrorLogCollector.RingBufferSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.RingBufferSql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//Exception/Error)[1]', 'int'), rb.x.value('(//Exception/Severity)[1]', 'int')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers WHERE ring_buffer_type = N'RING_BUFFER_EXCEPTION') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere, kilde 3: mislykkede logins fra connectivity ring buffer
|
||||
-- Kilde: ErrorLogCollector.ConnectivitySql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ErrorLogCollector.cs : ErrorLogCollector.ConnectivitySql
|
||||
SELECT DATEADD(millisecond, -CAST((i.ms_ticks - rb.timestamp) % 1000 AS int), DATEADD(second, -CAST((i.ms_ticks - rb.timestamp) / 1000 AS int), GETUTCDATE())),
|
||||
rb.x.value('(//SniConsumerError)[1]', 'int'), rb.x.value('(//State)[1]', 'int'), rb.x.value('(//RemoteHost)[1]', 'nvarchar(128)')
|
||||
FROM (SELECT timestamp, CAST(record AS xml) AS x FROM sys.dm_os_ring_buffers
|
||||
WHERE ring_buffer_type = N'RING_BUFFER_CONNECTIVITY' AND record LIKE N'%<SniConsumerError>18456</SniConsumerError>%') rb
|
||||
CROSS JOIN sys.dm_os_sys_info i
|
||||
GO
|
||||
137
SQL Scripts/SQLI-MEM-001.sql
Normal file
137
SQL Scripts/SQLI-MEM-001.sql
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-MEM-001: Forespørgsler venter på hukommelse
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-MEM-001
|
||||
-- Titel: Forespørgsler venter på hukommelse
|
||||
-- Alvor: High
|
||||
-- Versioner: Alle (SQL Server 2000 via master.dbo.sysperfinfo).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om forespørgsler står i kø for at få tildelt hukommelse (RESOURCE_SEMAPHORE), før de kan starte.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis tælleren 'Memory Grants Pending' (øjebliksværdi) > 0, eller RESOURCE_SEMAPHORE har ventet mindst 10.000
|
||||
-- ms i intervallet mellem to ventetidsmålinger.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Pending > 0 eller >= 10.000 ms RESOURCE_SEMAPHORE (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- PerformanceCounterCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/PerformanceCounterCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), PerformanceCounterCollector.BuildSql(dmv: true),
|
||||
-- PerformanceCounterCollector.BuildSql(dmv: false)
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:performance-counters)
|
||||
-- Delt script: SQL Scripts/_collectors/PerformanceCounterCollector.sql
|
||||
-- WaitStatsCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), WaitStatsCollector.Sql2005, WaitStatsCollector.Sql2000
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:wait-stats)
|
||||
-- Delt script: SQL Scripts/_collectors/WaitStatsCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/ResourceRules.cs : MemoryGrantsPendingRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt DBCC SQLPERF(WAITSTATS) (læser ventetider, SQL Server 2000),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- PerformanceCounterCollector: Udvalgte performance counters: memory grants, page life expectancy, forbindelser,
|
||||
-- blokerede processer, batch requests og kompileringer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt
|
||||
-- Kilde: PerformanceCounterCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: PerformanceCounterCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: PerformanceCounterCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: PerformanceCounterCollector.BuildSql(dmv)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PerformanceCounterCollector.cs : PerformanceCounterCollector.BuildSql(dmv: true)
|
||||
SELECT RTRIM(object_name), RTRIM(counter_name), CAST(cntr_value AS bigint)
|
||||
FROM sys.dm_os_performance_counters
|
||||
WHERE (object_name LIKE N'%Memory Manager%' AND counter_name IN (N'Memory Grants Pending', N'Memory Grants Outstanding'))
|
||||
OR (object_name LIKE N'%Buffer Manager%' AND counter_name = N'Page life expectancy')
|
||||
OR (object_name LIKE N'%General Statistics%' AND counter_name IN (N'User Connections', N'Processes blocked'))
|
||||
OR (object_name LIKE N'%SQL Statistics%' AND counter_name IN (N'Batch Requests/sec', N'SQL Compilations/sec', N'SQL Re-Compilations/sec'))
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: PerformanceCounterCollector.BuildSql(sysperfinfo)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PerformanceCounterCollector.cs : PerformanceCounterCollector.BuildSql(dmv: false)
|
||||
SELECT RTRIM(object_name), RTRIM(counter_name), CAST(cntr_value AS bigint)
|
||||
FROM master.dbo.sysperfinfo
|
||||
WHERE (object_name LIKE N'%Memory Manager%' AND counter_name IN (N'Memory Grants Pending', N'Memory Grants Outstanding'))
|
||||
OR (object_name LIKE N'%Buffer Manager%' AND counter_name = N'Page life expectancy')
|
||||
OR (object_name LIKE N'%General Statistics%' AND counter_name IN (N'User Connections', N'Processes blocked'))
|
||||
OR (object_name LIKE N'%SQL Statistics%' AND counter_name IN (N'Batch Requests/sec', N'SQL Compilations/sec', N'SQL Re-Compilations/sec'))
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- WaitStatsCollector: Kumulative ventetider. Reglerne bruger forskellen mellem to målinger; en genstart (nyt
|
||||
-- starttidspunkt) nulstiller.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt (nulstilling af kumulative tal)
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: WaitStatsCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2005
|
||||
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
|
||||
FROM sys.dm_os_wait_stats
|
||||
WHERE wait_time_ms > 0
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: WaitStatsCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2000
|
||||
DBCC SQLPERF(WAITSTATS) WITH NO_INFOMSGS
|
||||
GO
|
||||
66
SQL Scripts/SQLI-OPS-001.sql
Normal file
66
SQL Scripts/SQLI-OPS-001.sql
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-OPS-001: Backup eller restore kører markant længere end normalt
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-OPS-001
|
||||
-- Titel: Backup eller restore kører markant længere end normalt
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en backup eller restore kører markant længere end samme kommando på samme database plejer.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Hvert minut læses de kørende operationer med percent_complete > 0. Afsluttede operationer på mindst 1 minut
|
||||
-- huskes (de seneste 10 pr. kommando og database). Fund for kørende BACKUP/RESTORE, når der er mindst 3 tidligere
|
||||
-- kørsler, og den har kørt mere end 2 x medianen og mindst 5 minutter længere end medianen.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Faktor 2 (SlowBackupRule.Factor); mindst 5 minutter over medianen; mindst 3 tidligere kørsler (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- LongOperationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/LongOperationCollector.cs
|
||||
-- Medlemmer: LongOperationCollector.Sql
|
||||
-- Interval: 1 min som standard (SQLInsight:CollectorIntervals:long-operations)
|
||||
-- Delt script: SQL Scripts/_collectors/LongOperationCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/OperationRules.cs : SlowBackupRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- LongOperationCollector: Operationer, SQL Server rapporterer fremdrift for (BACKUP, RESTORE, DBCC, ALTER INDEX
|
||||
-- REORGANIZE, SHRINK, ROLLBACK ...).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: LongOperationCollector.Sql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/LongOperationCollector.cs : LongOperationCollector.Sql
|
||||
SELECT r.session_id, r.command, DB_NAME(r.database_id), s.login_name,
|
||||
DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), r.start_time),
|
||||
CAST(r.percent_complete AS float),
|
||||
CASE WHEN r.estimated_completion_time > 0 THEN DATEADD(second, CAST(r.estimated_completion_time / 1000 AS int), GETUTCDATE()) END,
|
||||
GETUTCDATE()
|
||||
FROM sys.dm_exec_requests r
|
||||
LEFT JOIN sys.dm_exec_sessions s ON s.session_id = r.session_id
|
||||
WHERE r.percent_complete > 0 AND r.session_id <> @@SPID
|
||||
GO
|
||||
127
SQL Scripts/SQLI-PLAN-001.sql
Normal file
127
SQL Scripts/SQLI-PLAN-001.sql
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-PLAN-001: Implicit konvertering forhindrer index seek
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-PLAN-001
|
||||
-- Titel: Implicit konvertering forhindrer index seek
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 SP2 og nyere (sys.dm_exec_text_query_plan).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en tung forespørgsel har en implicit konvertering, der forhindrer index seek.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- De 50 sætninger med mest CPU (kørt det seneste døgn) får deres cachede plan analyseret i C# (ShowplanAnalyzer;
|
||||
-- planer over 4 MB springes over): fund hvis planen har PlanAffectingConvert med ConvertIssue = "Seek Plan". Højst
|
||||
-- 10 fund, mest CPU først.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Top 50 (PlanAnalysisCollector.TopStatements); 10 fund (PlanRule.MaxFindingsPerRule), fast i koden.
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- PlanAnalysisCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs
|
||||
-- Medlemmer: PlanAnalysisCollector.BuildSql(memoryColumns: true, queryHash: true),
|
||||
-- PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: true),
|
||||
-- PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: false)
|
||||
-- Interval: 30 min som standard (SQLInsight:CollectorIntervals:plan-analysis)
|
||||
-- Delt script: SQL Scripts/_collectors/PlanAnalysisCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/PlanRules.cs : ImplicitConversionRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- PlanAnalysisCollector: De 50 sætninger med mest CPU det seneste døgn og deres cachede planer (som tekst), som
|
||||
-- analyseres i C# (ShowplanAnalyzer).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 / 2017 CU3 og nyere (med spill- og memory grant-kolonner)
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: true, queryHash: true)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT CONVERT(varchar(20), qs.query_hash, 1),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
qs.total_spills, qs.total_grant_kb, qs.total_used_grant_kb,
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 – 2016 SP1 og 2017 før CU3
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2008)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: true)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT CONVERT(varchar(20), qs.query_hash, 1),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
CAST(NULL AS bigint), CAST(NULL AS bigint), CAST(NULL AS bigint),
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 SP2 og nyere 2005-builds
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: false)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT sys.fn_varbintohexstr(qs.sql_handle) + ':' + CAST(qs.statement_start_offset AS varchar(12)) + ':' + CAST(qs.statement_end_offset AS varchar(12)),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
CAST(NULL AS bigint), CAST(NULL AS bigint), CAST(NULL AS bigint),
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
126
SQL Scripts/SQLI-PLAN-002.sql
Normal file
126
SQL Scripts/SQLI-PLAN-002.sql
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-PLAN-002: Join uden join-betingelse (kartesisk produkt)
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-PLAN-002
|
||||
-- Titel: Join uden join-betingelse (kartesisk produkt)
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2005 SP2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en tung forespørgsel joiner uden join-betingelse (utilsigtet kartesisk produkt).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Planen analyseres i C#: fund hvis den har en Warnings-node med NoJoinPredicate = true, og sætningsteksten ikke
|
||||
-- indeholder CROSS JOIN (bevidst). Højst 10 fund.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Top 50 sætninger; 10 fund (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- PlanAnalysisCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs
|
||||
-- Medlemmer: PlanAnalysisCollector.BuildSql(memoryColumns: true, queryHash: true),
|
||||
-- PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: true),
|
||||
-- PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: false)
|
||||
-- Interval: 30 min som standard (SQLInsight:CollectorIntervals:plan-analysis)
|
||||
-- Delt script: SQL Scripts/_collectors/PlanAnalysisCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/PlanRules.cs : NoJoinPredicateRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- PlanAnalysisCollector: De 50 sætninger med mest CPU det seneste døgn og deres cachede planer (som tekst), som
|
||||
-- analyseres i C# (ShowplanAnalyzer).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 / 2017 CU3 og nyere (med spill- og memory grant-kolonner)
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: true, queryHash: true)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT CONVERT(varchar(20), qs.query_hash, 1),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
qs.total_spills, qs.total_grant_kb, qs.total_used_grant_kb,
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 – 2016 SP1 og 2017 før CU3
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2008)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: true)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT CONVERT(varchar(20), qs.query_hash, 1),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
CAST(NULL AS bigint), CAST(NULL AS bigint), CAST(NULL AS bigint),
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 SP2 og nyere 2005-builds
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: false)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT sys.fn_varbintohexstr(qs.sql_handle) + ':' + CAST(qs.statement_start_offset AS varchar(12)) + ':' + CAST(qs.statement_end_offset AS varchar(12)),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
CAST(NULL AS bigint), CAST(NULL AS bigint), CAST(NULL AS bigint),
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
126
SQL Scripts/SQLI-PLAN-003.sql
Normal file
126
SQL Scripts/SQLI-PLAN-003.sql
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-PLAN-003: Skalar funktion kaldes for hver række
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-PLAN-003
|
||||
-- Titel: Skalar funktion kaldes for hver række
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 SP2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en tung forespørgsel kalder en skalar brugerfunktion for hver række.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Planen analyseres i C#: fund hvis den indeholder UserDefinedFunction-noder, og sætningens samlede CPU-tid er
|
||||
-- mindst 60 sekunder. Højst 10 fund.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 60.000.000 µs CPU (ScalarUdfRule.MinTotalWorkerTimeUs, fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- PlanAnalysisCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs
|
||||
-- Medlemmer: PlanAnalysisCollector.BuildSql(memoryColumns: true, queryHash: true),
|
||||
-- PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: true),
|
||||
-- PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: false)
|
||||
-- Interval: 30 min som standard (SQLInsight:CollectorIntervals:plan-analysis)
|
||||
-- Delt script: SQL Scripts/_collectors/PlanAnalysisCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/PlanRules.cs : ScalarUdfRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- PlanAnalysisCollector: De 50 sætninger med mest CPU det seneste døgn og deres cachede planer (som tekst), som
|
||||
-- analyseres i C# (ShowplanAnalyzer).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 / 2017 CU3 og nyere (med spill- og memory grant-kolonner)
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: true, queryHash: true)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT CONVERT(varchar(20), qs.query_hash, 1),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
qs.total_spills, qs.total_grant_kb, qs.total_used_grant_kb,
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 – 2016 SP1 og 2017 før CU3
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2008)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: true)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT CONVERT(varchar(20), qs.query_hash, 1),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
CAST(NULL AS bigint), CAST(NULL AS bigint), CAST(NULL AS bigint),
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 SP2 og nyere 2005-builds
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: false)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT sys.fn_varbintohexstr(qs.sql_handle) + ':' + CAST(qs.statement_start_offset AS varchar(12)) + ':' + CAST(qs.statement_end_offset AS varchar(12)),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
CAST(NULL AS bigint), CAST(NULL AS bigint), CAST(NULL AS bigint),
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
126
SQL Scripts/SQLI-PLAN-004.sql
Normal file
126
SQL Scripts/SQLI-PLAN-004.sql
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-PLAN-004: Sorteringer og hash joins spilder til tempdb
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-PLAN-004
|
||||
-- Titel: Sorteringer og hash joins spilder til tempdb
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2016 SP2 / 2017 CU3 og nyere (total_spills i sys.dm_exec_query_stats). Ældre: "tjek
|
||||
-- manuelt".
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om sorteringer og hash joins i en tung forespørgsel spilder til tempdb.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis total_spills / execution_count >= 1.024 sider (ca. 8 MB) pr. udførelse. Højst 10 fund.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 1.024 sider pr. udførelse (SpillRule.MinSpillPagesPerExecution, fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- PlanAnalysisCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs
|
||||
-- Medlemmer: PlanAnalysisCollector.BuildSql(memoryColumns: true, queryHash: true),
|
||||
-- PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: true),
|
||||
-- PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: false)
|
||||
-- Interval: 30 min som standard (SQLInsight:CollectorIntervals:plan-analysis)
|
||||
-- Delt script: SQL Scripts/_collectors/PlanAnalysisCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/PlanRules.cs : SpillRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- PlanAnalysisCollector: De 50 sætninger med mest CPU det seneste døgn og deres cachede planer (som tekst), som
|
||||
-- analyseres i C# (ShowplanAnalyzer).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 / 2017 CU3 og nyere (med spill- og memory grant-kolonner)
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: true, queryHash: true)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT CONVERT(varchar(20), qs.query_hash, 1),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
qs.total_spills, qs.total_grant_kb, qs.total_used_grant_kb,
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 – 2016 SP1 og 2017 før CU3
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2008)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: true)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT CONVERT(varchar(20), qs.query_hash, 1),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
CAST(NULL AS bigint), CAST(NULL AS bigint), CAST(NULL AS bigint),
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 SP2 og nyere 2005-builds
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: false)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT sys.fn_varbintohexstr(qs.sql_handle) + ':' + CAST(qs.statement_start_offset AS varchar(12)) + ':' + CAST(qs.statement_end_offset AS varchar(12)),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
CAST(NULL AS bigint), CAST(NULL AS bigint), CAST(NULL AS bigint),
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
126
SQL Scripts/SQLI-PLAN-005.sql
Normal file
126
SQL Scripts/SQLI-PLAN-005.sql
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-PLAN-005: Forespørgsel får langt mere hukommelse, end den bruger
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-PLAN-005
|
||||
-- Titel: Forespørgsel får langt mere hukommelse, end den bruger
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2016 SP2 / 2017 CU3 og nyere (total_grant_kb, total_used_grant_kb). Ældre: "tjek manuelt".
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en forespørgsel får tildelt langt mere hukommelse, end den bruger.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis gennemsnitlig tildeling (total_grant_kb / execution_count) >= 100 MB, og brugt (total_used_grant_kb) <=
|
||||
-- 10 % af tildelt. Højst 10 fund.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 102.400 KB pr. udførelse (ExcessiveGrantRule.MinAverageGrantKb) og 10 % (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- PlanAnalysisCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs
|
||||
-- Medlemmer: PlanAnalysisCollector.BuildSql(memoryColumns: true, queryHash: true),
|
||||
-- PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: true),
|
||||
-- PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: false)
|
||||
-- Interval: 30 min som standard (SQLInsight:CollectorIntervals:plan-analysis)
|
||||
-- Delt script: SQL Scripts/_collectors/PlanAnalysisCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/PlanRules.cs : ExcessiveGrantRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- PlanAnalysisCollector: De 50 sætninger med mest CPU det seneste døgn og deres cachede planer (som tekst), som
|
||||
-- analyseres i C# (ShowplanAnalyzer).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 / 2017 CU3 og nyere (med spill- og memory grant-kolonner)
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: true, queryHash: true)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT CONVERT(varchar(20), qs.query_hash, 1),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
qs.total_spills, qs.total_grant_kb, qs.total_used_grant_kb,
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 – 2016 SP1 og 2017 før CU3
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2008)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: true)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT CONVERT(varchar(20), qs.query_hash, 1),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
CAST(NULL AS bigint), CAST(NULL AS bigint), CAST(NULL AS bigint),
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 SP2 og nyere 2005-builds
|
||||
-- Kilde: PlanAnalysisCollector.BuildSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/PlanAnalysisCollector.cs : PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: false)
|
||||
WITH top_statements AS (
|
||||
SELECT TOP (50) qs.*
|
||||
FROM sys.dm_exec_query_stats qs
|
||||
WHERE qs.last_execution_time >= DATEADD(hour, -24, GETDATE())
|
||||
ORDER BY qs.total_worker_time DESC
|
||||
)
|
||||
SELECT sys.fn_varbintohexstr(qs.sql_handle) + ':' + CAST(qs.statement_start_offset AS varchar(12)) + ':' + CAST(qs.statement_end_offset AS varchar(12)),
|
||||
DB_NAME(CONVERT(int, pa.value)),
|
||||
LEFT(SUBSTRING(t.text, qs.statement_start_offset / 2 + 1,
|
||||
(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(t.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2 + 1), 4000),
|
||||
qs.execution_count, qs.total_worker_time, qs.total_elapsed_time, qs.total_logical_reads,
|
||||
CAST(NULL AS bigint), CAST(NULL AS bigint), CAST(NULL AS bigint),
|
||||
qs.last_execution_time,
|
||||
tp.query_plan
|
||||
FROM top_statements qs
|
||||
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
|
||||
OUTER APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) tp
|
||||
OUTER APPLY (SELECT value FROM sys.dm_exec_plan_attributes(qs.plan_handle) WHERE attribute = N'dbid') pa
|
||||
ORDER BY qs.total_worker_time DESC;
|
||||
GO
|
||||
116
SQL Scripts/SQLI-QS-001.sql
Normal file
116
SQL Scripts/SQLI-QS-001.sql
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-QS-001: Planregression: forespørgsel har fået en langsommere plan
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-QS-001
|
||||
-- Titel: Planregression: forespørgsel har fået en langsommere plan
|
||||
-- Alvor: Medium; High når ekstra tid er mindst 10 minutter i døgnet.
|
||||
-- Versioner: SQL Server 2016 og nyere (Query Store), i databaser med Query Store slået til.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en forespørgsel har fået en ny plan det seneste døgn, der er markant langsommere end dens bedste plan ugen
|
||||
-- før.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Collectoren henter de 100 tungeste queries (samlet varighed over 8 dage) pr. database, opdelt i seneste døgn og
|
||||
-- ugen før. Bedste plan = laveste gns. varighed før det seneste døgn med mindst 10 udførelser. Fund når en anden
|
||||
-- plan i seneste døgn med mindst 10 udførelser er mindst 2 x langsommere og koster mindst 60 s ekstra i alt ((gns.
|
||||
-- ny - gns. bedste) x udførelser). Højst 10 fund, største ekstra tid først.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 10 udførelser, faktor 2, 60 s ekstra (PlanRegressionRule-konstanter, fast i koden); 100 queries pr. database
|
||||
-- (QueryStoreCollector.TopQueries).
|
||||
--
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- QueryStoreCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/QueryStoreCollector.cs
|
||||
-- Medlemmer: QueryStoreCollector.DatabasesSql, QueryStoreCollector.BuildStatsSql(database),
|
||||
-- QueryStoreCollector.BuildFailedForcedSql(database)
|
||||
-- Interval: 30 min som standard (SQLInsight:CollectorIntervals:query-store)
|
||||
-- Delt script: SQL Scripts/_collectors/QueryStoreCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/QueryStoreRules.cs : PlanRegressionRule.Evaluate
|
||||
--
|
||||
-- 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 (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- QueryStoreCollector: Query Store i hver brugerdatabase, hvor det er slået til: de 100 tungeste queries over 8 dage
|
||||
-- og forcerede planer, der fejler.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- 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
|
||||
111
SQL Scripts/SQLI-QS-002.sql
Normal file
111
SQL Scripts/SQLI-QS-002.sql
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-QS-002: Forceret plan kan ikke bruges
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-QS-002
|
||||
-- Titel: Forceret plan kan ikke bruges
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2016 og nyere (Query Store).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en plan, der er forceret i Query Store, ikke længere kan bruges (fx fordi et index er fjernet).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund pr. plan med is_forced_plan = 1 og force_failure_count > 0 (højst 10).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- QueryStoreCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/QueryStoreCollector.cs
|
||||
-- Medlemmer: QueryStoreCollector.DatabasesSql, QueryStoreCollector.BuildStatsSql(database),
|
||||
-- QueryStoreCollector.BuildFailedForcedSql(database)
|
||||
-- Interval: 30 min som standard (SQLInsight:CollectorIntervals:query-store)
|
||||
-- Delt script: SQL Scripts/_collectors/QueryStoreCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/QueryStoreRules.cs : FailedForcedPlanRule.Evaluate
|
||||
--
|
||||
-- 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 (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- QueryStoreCollector: Query Store i hver brugerdatabase, hvor det er slået til: de 100 tungeste queries over 8 dage
|
||||
-- og forcerede planer, der fejler.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- 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
|
||||
115
SQL Scripts/SQLI-QS-003.sql
Normal file
115
SQL Scripts/SQLI-QS-003.sql
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-QS-003: Parameterfølsom forespørgsel (parameter sniffing)
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-QS-003
|
||||
-- Titel: Parameterfølsom forespørgsel (parameter sniffing)
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2016 og nyere (Query Store).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en forespørgsel har meget svingende svartider eller skifter mellem meget forskellige planer (parameter
|
||||
-- sniffing).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For hver query i seneste døgn, planer med mindst 10 udførelser. Fund hvis (a) mindst 2 planer, hvor den
|
||||
-- langsomste i gennemsnit er mindst 10 x den hurtigste og mindst 100 ms, eller (b) den mest brugte plan har mindst
|
||||
-- 100 udførelser, max-varighed >= 1 s, max/gns. >= 20 og max stdev/gns. >= 2. Højst 10 fund, mest samlet varighed
|
||||
-- først.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 100 udførelser og 1 s (ParameterSensitivityRule-konstanter) samt faktorerne 10, 20 og 2 (fast i koden).
|
||||
--
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- QueryStoreCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/QueryStoreCollector.cs
|
||||
-- Medlemmer: QueryStoreCollector.DatabasesSql, QueryStoreCollector.BuildStatsSql(database),
|
||||
-- QueryStoreCollector.BuildFailedForcedSql(database)
|
||||
-- Interval: 30 min som standard (SQLInsight:CollectorIntervals:query-store)
|
||||
-- Delt script: SQL Scripts/_collectors/QueryStoreCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/QueryStoreRules.cs : ParameterSensitivityRule.Evaluate
|
||||
--
|
||||
-- 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 (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- QueryStoreCollector: Query Store i hver brugerdatabase, hvor det er slået til: de 100 tungeste queries over 8 dage
|
||||
-- og forcerede planer, der fejler.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- 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
|
||||
88
SQL Scripts/SQLI-REPL-001.sql
Normal file
88
SQL Scripts/SQLI-REPL-001.sql
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-REPL-001: Replikering fejler
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-REPL-001
|
||||
-- Titel: Replikering fejler
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2005 og nyere. Kun relevant på en distributør (sys.databases.is_distributor = 1); kræver
|
||||
-- SELECT på tre tabeller i distributionsdatabasen, ellers "ikke målbar" med vejledning.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en distributionsagent er fejlet eller bliver ved med at prøve igen.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For hver distributionsagent læses seneste historikpost (MSdistribution_history, højeste timestamp). Fund hvis
|
||||
-- runstatus er 5 (retry) eller 6 (fejl).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- GRANT VIEW ANY DEFINITION TO [agent]; -- metadata; giver IKKE adgang til data
|
||||
-- Kun på en distributør, valgfrit (gives ikke af grant-least-privilege.sql):
|
||||
-- USE distribution; CREATE USER [agent] FOR LOGIN [agent];
|
||||
-- GRANT SELECT ON dbo.MSdistribution_agents TO [agent]; GRANT SELECT ON dbo.MSdistribution_history TO [agent]; GRANT SELECT ON dbo.MSrepl_errors TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ReplicationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ReplicationCollector.cs
|
||||
-- Medlemmer: ReplicationCollector.DistributionDatabaseSql, Db.CurrentDatabaseSql,
|
||||
-- ReplicationCollector.AgentsSql, ReplicationCollector.ErrorsSql
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:replication)
|
||||
-- Delt script: SQL Scripts/_collectors/ReplicationCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Availability/ReplicationRules.cs : ReplicationAgentFailedRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ReplicationCollector: På en distributør: hver distributionsagents seneste status, forsinkelse og besked samt
|
||||
-- replikeringsfejl det seneste døgn.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ReplicationCollector.DistributionDatabaseSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ReplicationCollector.cs : ReplicationCollector.DistributionDatabaseSql
|
||||
SELECT TOP 1 name FROM sys.databases WHERE is_distributor = 1 AND state = 0
|
||||
GO
|
||||
|
||||
-- Variant: Kun på en distributør: husk databasen, der skal skiftes tilbage til
|
||||
-- Kilde: ReplicationCollector.CurrentDatabaseSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.CurrentDatabaseSql
|
||||
SELECT DB_NAME()
|
||||
GO
|
||||
|
||||
-- Variant: Kun på en distributør, i distributionsdatabasen
|
||||
-- Kilde: ReplicationCollector.AgentsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ReplicationCollector.cs : ReplicationCollector.AgentsSql
|
||||
-- Agenten sender "USE [<distributionsdatabasen>];" foran (navnet fra DistributionDatabaseSql). Ret navnet, hvis det ikke er distribution.
|
||||
USE [distribution];
|
||||
SELECT TOP 500 a.name, a.publisher_db, h.runstatus, DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), h.time), h.delivery_latency,
|
||||
CAST(h.comments AS nvarchar(500))
|
||||
FROM dbo.MSdistribution_agents a
|
||||
OUTER APPLY (SELECT TOP 1 x.runstatus, x.time, x.delivery_latency, x.comments FROM dbo.MSdistribution_history x
|
||||
WHERE x.agent_id = a.id ORDER BY x.timestamp DESC) h
|
||||
GO
|
||||
|
||||
-- Variant: Kun på en distributør, i distributionsdatabasen
|
||||
-- Kilde: ReplicationCollector.ErrorsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ReplicationCollector.cs : ReplicationCollector.ErrorsSql
|
||||
-- Agenten sender "USE [<distributionsdatabasen>];" foran (navnet fra DistributionDatabaseSql). Ret navnet, hvis det ikke er distribution.
|
||||
USE [distribution];
|
||||
SELECT COUNT(*) FROM dbo.MSrepl_errors WHERE time > DATEADD(hour, -24, GETDATE())
|
||||
GO
|
||||
86
SQL Scripts/SQLI-REPL-002.sql
Normal file
86
SQL Scripts/SQLI-REPL-002.sql
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-REPL-002: Replikering er forsinket
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-REPL-002
|
||||
-- Titel: Replikering er forsinket
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere, kun på en distributør (som SQLI-REPL-001).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om ændringer tager lang tid om at nå abonnenten.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund for agenter, der ikke er fejlet, hvor delivery_latency i seneste historikpost er mindst 5 minutter.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 300.000 ms (ReplicationSnapshot.LatencyThresholdMs, fast i koden).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- GRANT VIEW ANY DEFINITION TO [agent]; -- metadata; giver IKKE adgang til data
|
||||
-- Kun på en distributør, valgfrit (gives ikke af grant-least-privilege.sql):
|
||||
-- USE distribution; CREATE USER [agent] FOR LOGIN [agent];
|
||||
-- GRANT SELECT ON dbo.MSdistribution_agents TO [agent]; GRANT SELECT ON dbo.MSdistribution_history TO [agent]; GRANT SELECT ON dbo.MSrepl_errors TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ReplicationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/ReplicationCollector.cs
|
||||
-- Medlemmer: ReplicationCollector.DistributionDatabaseSql, Db.CurrentDatabaseSql,
|
||||
-- ReplicationCollector.AgentsSql, ReplicationCollector.ErrorsSql
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:replication)
|
||||
-- Delt script: SQL Scripts/_collectors/ReplicationCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Availability/ReplicationRules.cs : ReplicationLatencyRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt USE (skifter sessionens database), SET-sessionsindstillinger. Intet ændrer data,
|
||||
-- indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ReplicationCollector: På en distributør: hver distributionsagents seneste status, forsinkelse og besked samt
|
||||
-- replikeringsfejl det seneste døgn.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: ReplicationCollector.DistributionDatabaseSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ReplicationCollector.cs : ReplicationCollector.DistributionDatabaseSql
|
||||
SELECT TOP 1 name FROM sys.databases WHERE is_distributor = 1 AND state = 0
|
||||
GO
|
||||
|
||||
-- Variant: Kun på en distributør: husk databasen, der skal skiftes tilbage til
|
||||
-- Kilde: ReplicationCollector.CurrentDatabaseSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.CurrentDatabaseSql
|
||||
SELECT DB_NAME()
|
||||
GO
|
||||
|
||||
-- Variant: Kun på en distributør, i distributionsdatabasen
|
||||
-- Kilde: ReplicationCollector.AgentsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ReplicationCollector.cs : ReplicationCollector.AgentsSql
|
||||
-- Agenten sender "USE [<distributionsdatabasen>];" foran (navnet fra DistributionDatabaseSql). Ret navnet, hvis det ikke er distribution.
|
||||
USE [distribution];
|
||||
SELECT TOP 500 a.name, a.publisher_db, h.runstatus, DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), h.time), h.delivery_latency,
|
||||
CAST(h.comments AS nvarchar(500))
|
||||
FROM dbo.MSdistribution_agents a
|
||||
OUTER APPLY (SELECT TOP 1 x.runstatus, x.time, x.delivery_latency, x.comments FROM dbo.MSdistribution_history x
|
||||
WHERE x.agent_id = a.id ORDER BY x.timestamp DESC) h
|
||||
GO
|
||||
|
||||
-- Variant: Kun på en distributør, i distributionsdatabasen
|
||||
-- Kilde: ReplicationCollector.ErrorsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ReplicationCollector.cs : ReplicationCollector.ErrorsSql
|
||||
-- Agenten sender "USE [<distributionsdatabasen>];" foran (navnet fra DistributionDatabaseSql). Ret navnet, hvis det ikke er distribution.
|
||||
USE [distribution];
|
||||
SELECT COUNT(*) FROM dbo.MSrepl_errors WHERE time > DATEADD(hour, -24, GETDATE())
|
||||
GO
|
||||
93
SQL Scripts/SQLI-REQ-001.sql
Normal file
93
SQL Scripts/SQLI-REQ-001.sql
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-REQ-001: Sætning har kørt længe
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-REQ-001
|
||||
-- Titel: Sætning har kørt længe
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en brugersætning har kørt længe og måske holder låse, som andre venter på.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- SQL'en finder requests med total_elapsed_time over grænsen og percent_complete = 0. I C# fjernes BACKUP, RESTORE
|
||||
-- og DBCC (de er langvarige operationer) og requests, der venter med en godartet ventetype (WAITFOR, Service Broker
|
||||
-- m.fl.). Fund for op til 10, længst kørende først.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:Activity:RequestMinutes, standard 15 (minutter) = 900000 ms i SQL'en.
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ActivityCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Concurrency/ActivityCollector.cs
|
||||
-- Medlemmer: ActivityCollector.BuildTransactionsSql(1024) = TransactionsSql udfyldt,
|
||||
-- ActivityCollector.BuildLongRequestsSql(15) = LongRequestsSql udfyldt
|
||||
-- Interval: 1 min som standard (SQLInsight:CollectorIntervals:activity)
|
||||
-- Delt script: SQL Scripts/_collectors/ActivityCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Concurrency/ActivityRules.cs : LongRunningStatementRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ActivityCollector: Åbne brugertransaktioner (alder, log) og brugersætninger, der har kørt længere end grænsen.
|
||||
-- Agentens egne sessioner er udeladt.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere (vist med standardgrænsen 1024 MB log)
|
||||
-- Kilde: ActivityCollector.BuildTransactionsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Concurrency/ActivityCollector.cs : ActivityCollector.BuildTransactionsSql(1024) = TransactionsSql udfyldt
|
||||
SELECT TOP 100 t.session_id, t.transaction_id, t.name, DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), t.begin_time),
|
||||
t.used, t.reserved, t.db, t.dbs, s.login_name, s.host_name, s.program_name, s.status, r.wait_type,
|
||||
CAST(CASE WHEN r.sql_handle IS NOT NULL
|
||||
THEN SUBSTRING(q.text, r.statement_start_offset / 2 + 1,
|
||||
CASE WHEN r.statement_end_offset = -1 THEN 1000 ELSE (r.statement_end_offset - r.statement_start_offset) / 2 + 1 END)
|
||||
ELSE LEFT(q.text, 1000) END AS nvarchar(1000))
|
||||
FROM (SELECT st.session_id, at.transaction_id, MAX(at.name) AS name, MIN(at.transaction_begin_time) AS begin_time,
|
||||
ISNULL(SUM(dt.database_transaction_log_bytes_used), 0) AS used, ISNULL(SUM(dt.database_transaction_log_bytes_reserved), 0) AS reserved,
|
||||
MIN(DB_NAME(dt.database_id)) AS db, COUNT(DISTINCT dt.database_id) AS dbs
|
||||
FROM sys.dm_tran_session_transactions st
|
||||
JOIN sys.dm_tran_active_transactions at ON at.transaction_id = st.transaction_id
|
||||
LEFT JOIN sys.dm_tran_database_transactions dt ON dt.transaction_id = st.transaction_id AND dt.database_id <> 32767
|
||||
GROUP BY st.session_id, at.transaction_id) t
|
||||
JOIN sys.dm_exec_sessions s ON s.session_id = t.session_id
|
||||
OUTER APPLY (SELECT TOP 1 x.sql_handle, x.statement_start_offset, x.statement_end_offset, x.wait_type FROM sys.dm_exec_requests x
|
||||
WHERE x.session_id = t.session_id ORDER BY x.request_id) r
|
||||
OUTER APPLY (SELECT TOP 1 c.most_recent_sql_handle FROM sys.dm_exec_connections c WHERE c.session_id = t.session_id) c
|
||||
OUTER APPLY sys.dm_exec_sql_text(COALESCE(r.sql_handle, c.most_recent_sql_handle)) q
|
||||
WHERE s.is_user_process = 1 AND s.session_id <> @@SPID AND (s.program_name IS NULL OR s.program_name NOT LIKE N'SQLInsight Pro%') AND t.begin_time IS NOT NULL
|
||||
ORDER BY CASE WHEN t.used + t.reserved >= 1073741824 THEN 0 ELSE 1 END, t.begin_time
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere (vist med standardgrænsen 15 minutter)
|
||||
-- Kilde: ActivityCollector.BuildLongRequestsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Concurrency/ActivityCollector.cs : ActivityCollector.BuildLongRequestsSql(15) = LongRequestsSql udfyldt
|
||||
SELECT TOP 50 r.session_id, DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), r.start_time), r.total_elapsed_time, r.command, r.status,
|
||||
r.wait_type, r.wait_time, DB_NAME(r.database_id), s.login_name, s.host_name, s.program_name, r.blocking_session_id,
|
||||
CAST(SUBSTRING(q.text, r.statement_start_offset / 2 + 1,
|
||||
CASE WHEN r.statement_end_offset = -1 THEN 1000 ELSE (r.statement_end_offset - r.statement_start_offset) / 2 + 1 END) AS nvarchar(1000))
|
||||
FROM sys.dm_exec_requests r
|
||||
JOIN sys.dm_exec_sessions s ON s.session_id = r.session_id
|
||||
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) q
|
||||
WHERE s.is_user_process = 1 AND s.session_id <> @@SPID AND (s.program_name IS NULL OR s.program_name NOT LIKE N'SQLInsight Pro%') AND r.total_elapsed_time > 900000 AND r.percent_complete = 0
|
||||
ORDER BY r.total_elapsed_time DESC
|
||||
GO
|
||||
106
SQL Scripts/SQLI-SEC-001.sql
Normal file
106
SQL Scripts/SQLI-SEC-001.sql
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-SEC-001: Ny forhøjet rettighed på serveren
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-SEC-001
|
||||
-- Titel: Ny forhøjet rettighed på serveren
|
||||
-- Alvor: High for sysadmin, securityadmin og CONTROL SERVER; Medium for de øvrige faste serverroller.
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om nogen har fået sysadmin eller en anden forhøjet serverrettighed - direkte eller ved at blive meldt ind i en
|
||||
-- Windows-gruppe, der har den.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Medlemmer af de faste serverroller (sysadmin, securityadmin, serveradmin, setupadmin, processadmin, diskadmin,
|
||||
-- dbcreator, bulkadmin) og indehavere af CONTROL SERVER (GRANT/WITH GRANT) sammenlignes med forrige måling;
|
||||
-- Windows-grupper foldes ud til personer via Active Directory af agenten (ikke SQL). Nye rettigheder inden for de
|
||||
-- seneste 7 dage giver ét fund hver. Hvem og hvornår slås op i default trace (EventClass 104, 105, 108) fra en time
|
||||
-- før forrige måling - kun med ALTER TRACE; uden står "ukendt".
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Fundet holdes åbent i 7 dage (PrivilegeAnalysis.RecentWindow, fast i koden).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- GRANT VIEW ANY DEFINITION TO [agent]; -- metadata; giver IKKE adgang til data
|
||||
-- Valgfrit: GRANT ALTER TRACE TO [agent]; -- default trace (udkommenteret i grant-least-privilege.sql; uden den bruges næste kilde)
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- PrivilegeCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs
|
||||
-- Medlemmer: PrivilegeCollector.MembersSql, PrivilegeCollector.SqlLoginsSql,
|
||||
-- PrivilegeCollector.DefaultTraceEnabledSql, PrivilegeCollector.DefaultTracePathSql,
|
||||
-- PrivilegeCollector.BuildTraceSql(traceFileBase, sinceLocal)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:privileges)
|
||||
-- Delt script: SQL Scripts/_collectors/PrivilegeCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Security/PrivilegeRules.cs : NewPrivilegeRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt sys.fn_trace_gettable (læser default trace), SET-sessionsindstillinger. Intet
|
||||
-- ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- PrivilegeCollector: Medlemmer af de faste serverroller og indehavere af CONTROL SERVER, SQL-logins'
|
||||
-- password-politik og - med ALTER TRACE - hvem der ændrede rettighederne (default trace).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: PrivilegeCollector.MembersSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.MembersSql
|
||||
SELECT p.name, p.type, r.name, p.is_disabled
|
||||
FROM sys.server_role_members m
|
||||
JOIN sys.server_principals r ON r.principal_id = m.role_principal_id
|
||||
JOIN sys.server_principals p ON p.principal_id = m.member_principal_id
|
||||
WHERE r.name IN (N'sysadmin', N'securityadmin', N'serveradmin', N'setupadmin', N'processadmin', N'diskadmin', N'dbcreator', N'bulkadmin')
|
||||
UNION ALL
|
||||
SELECT p.name, p.type, N'CONTROL SERVER', p.is_disabled
|
||||
FROM sys.server_permissions sp
|
||||
JOIN sys.server_principals p ON p.principal_id = sp.grantee_principal_id
|
||||
WHERE sp.permission_name = N'CONTROL SERVER' AND sp.state IN ('G', 'W')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: PrivilegeCollector.SqlLoginsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.SqlLoginsSql
|
||||
SELECT name, is_disabled, is_policy_checked, is_expiration_checked, CASE WHEN principal_id = 1 THEN 1 ELSE 0 END
|
||||
FROM sys.sql_logins WHERE name NOT LIKE N'##%'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: PrivilegeCollector.DefaultTraceEnabledSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.DefaultTraceEnabledSql
|
||||
SELECT CAST(value_in_use AS int) FROM sys.configurations WHERE name = N'default trace enabled'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kun når der er fundet ændringer (kræver ALTER TRACE)
|
||||
-- Kilde: PrivilegeCollector.DefaultTracePathSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.DefaultTracePathSql
|
||||
SELECT path, DATEDIFF(minute, GETUTCDATE(), GETDATE()) FROM sys.traces WHERE is_default = 1
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kun når der er fundet ændringer (kræver ALTER TRACE)
|
||||
-- Kilde: PrivilegeCollector.BuildTraceSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.BuildTraceSql(traceFileBase, sinceLocal)
|
||||
-- Agenten indsætter default trace-filens sti (mappen + log.trc, så alle rollover-filer læses) og serverens lokale tid
|
||||
-- for en time før forrige måling som literaler. Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fil nvarchar(260);
|
||||
DECLARE @siden nvarchar(19);
|
||||
SELECT @fil = LEFT(path, LEN(path) - CHARINDEX(N'\', REVERSE(path)) + 1) + N'log.trc' FROM sys.traces WHERE is_default = 1;
|
||||
SET @siden = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SELECT StartTime, EventClass, EventSubClass, LoginName, TargetLoginName, RoleName
|
||||
FROM sys.fn_trace_gettable(@fil, DEFAULT)
|
||||
WHERE EventClass IN (104, 105, 108) AND StartTime >= @siden
|
||||
GO
|
||||
104
SQL Scripts/SQLI-SEC-002.sql
Normal file
104
SQL Scripts/SQLI-SEC-002.sql
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-SEC-002: For mange personer og konti med sysadmin
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-SEC-002
|
||||
-- Titel: For mange personer og konti med sysadmin
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om flere personer og konti har sysadmin end kundens egen grænse.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Aktive konti med sysadmin tælles: SQL- og Windows-logins direkte (ikke tjeneste-identiteter som NT SERVICE\...,
|
||||
-- NT AUTHORITY\..., ##MS_...## og konti, der ender på $) og de aktive personer i Windows-grupper med sysadmin
|
||||
-- (foldet ud via Active Directory af agenten). Fund hvis antallet > grænsen. Grupper, der ikke kunne foldes ud,
|
||||
-- nævnes i målingerne.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:Privileges:MaxSysadminAccounts, standard 3.
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- GRANT VIEW ANY DEFINITION TO [agent]; -- metadata; giver IKKE adgang til data
|
||||
-- Valgfrit: GRANT ALTER TRACE TO [agent]; -- default trace (udkommenteret i grant-least-privilege.sql; uden den bruges næste kilde)
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- PrivilegeCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs
|
||||
-- Medlemmer: PrivilegeCollector.MembersSql, PrivilegeCollector.SqlLoginsSql,
|
||||
-- PrivilegeCollector.DefaultTraceEnabledSql, PrivilegeCollector.DefaultTracePathSql,
|
||||
-- PrivilegeCollector.BuildTraceSql(traceFileBase, sinceLocal)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:privileges)
|
||||
-- Delt script: SQL Scripts/_collectors/PrivilegeCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Security/PrivilegeRules.cs : TooManySysadminsRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt sys.fn_trace_gettable (læser default trace), SET-sessionsindstillinger. Intet
|
||||
-- ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- PrivilegeCollector: Medlemmer af de faste serverroller og indehavere af CONTROL SERVER, SQL-logins'
|
||||
-- password-politik og - med ALTER TRACE - hvem der ændrede rettighederne (default trace).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: PrivilegeCollector.MembersSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.MembersSql
|
||||
SELECT p.name, p.type, r.name, p.is_disabled
|
||||
FROM sys.server_role_members m
|
||||
JOIN sys.server_principals r ON r.principal_id = m.role_principal_id
|
||||
JOIN sys.server_principals p ON p.principal_id = m.member_principal_id
|
||||
WHERE r.name IN (N'sysadmin', N'securityadmin', N'serveradmin', N'setupadmin', N'processadmin', N'diskadmin', N'dbcreator', N'bulkadmin')
|
||||
UNION ALL
|
||||
SELECT p.name, p.type, N'CONTROL SERVER', p.is_disabled
|
||||
FROM sys.server_permissions sp
|
||||
JOIN sys.server_principals p ON p.principal_id = sp.grantee_principal_id
|
||||
WHERE sp.permission_name = N'CONTROL SERVER' AND sp.state IN ('G', 'W')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: PrivilegeCollector.SqlLoginsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.SqlLoginsSql
|
||||
SELECT name, is_disabled, is_policy_checked, is_expiration_checked, CASE WHEN principal_id = 1 THEN 1 ELSE 0 END
|
||||
FROM sys.sql_logins WHERE name NOT LIKE N'##%'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: PrivilegeCollector.DefaultTraceEnabledSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.DefaultTraceEnabledSql
|
||||
SELECT CAST(value_in_use AS int) FROM sys.configurations WHERE name = N'default trace enabled'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kun når der er fundet ændringer (kræver ALTER TRACE)
|
||||
-- Kilde: PrivilegeCollector.DefaultTracePathSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.DefaultTracePathSql
|
||||
SELECT path, DATEDIFF(minute, GETUTCDATE(), GETDATE()) FROM sys.traces WHERE is_default = 1
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kun når der er fundet ændringer (kræver ALTER TRACE)
|
||||
-- Kilde: PrivilegeCollector.BuildTraceSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/PrivilegeCollector.cs : PrivilegeCollector.BuildTraceSql(traceFileBase, sinceLocal)
|
||||
-- Agenten indsætter default trace-filens sti (mappen + log.trc, så alle rollover-filer læses) og serverens lokale tid
|
||||
-- for en time før forrige måling som literaler. Her er de variabler, så scriptet kan køres i SSMS.
|
||||
DECLARE @fil nvarchar(260);
|
||||
DECLARE @siden nvarchar(19);
|
||||
SELECT @fil = LEFT(path, LEN(path) - CHARINDEX(N'\', REVERSE(path)) + 1) + N'log.trc' FROM sys.traces WHERE is_default = 1;
|
||||
SET @siden = CONVERT(nvarchar(19), DATEADD(hour, -1, GETDATE()), 126);
|
||||
SELECT StartTime, EventClass, EventSubClass, LoginName, TargetLoginName, RoleName
|
||||
FROM sys.fn_trace_gettable(@fil, DEFAULT)
|
||||
WHERE EventClass IN (104, 105, 108) AND StartTime >= @siden
|
||||
GO
|
||||
159
SQL Scripts/SQLI-STAT-001.sql
Normal file
159
SQL Scripts/SQLI-STAT-001.sql
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-STAT-001: Forældede statistikker på store tabeller
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-STAT-001
|
||||
-- Titel: Forældede statistikker på store tabeller
|
||||
-- Alvor: Low
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om statistikker på store tabeller er forældede eller aldrig opdateret.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fra sys.sysindexes (rowmodctr, som kun kræver metadata-adgang): fund hvis STATS_DATE er NULL og tabellen har
|
||||
-- rækker, eller tabellen har mindst 10.000 rækker og rowmodctr >= 20 % af rækkerne. Højst 10, aldrig opdaterede
|
||||
-- først.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 10.000 rækker (MinRows) og 20 % (MinModifiedShare), fast i koden.
|
||||
--
|
||||
-- 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];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- IndexCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/IndexCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), IndexCollector.DatabasesSql, IndexCollector.MissingSql,
|
||||
-- IndexCollector.BuildIndexSql(database, filteredIndexes: true), IndexCollector.BuildIndexSql(database,
|
||||
-- filteredIndexes: false), IndexCollector.BuildStatisticsSql(database)
|
||||
-- Interval: 6 timer som standard (SQLInsight:CollectorIntervals:indexes)
|
||||
-- Delt script: SQL Scripts/_collectors/IndexCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Indexes/IndexRules.cs : StaleStatisticsRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- IndexCollector: Index-inventar med brug, manglende index-forslag og statistikker for hver læsbar brugerdatabase.
|
||||
-- Kun metadata og DMV'er; ingen tabeldata, ingen scanning.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt
|
||||
-- Kilde: IndexCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: IndexCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: IndexCollector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.DatabasesSql
|
||||
SELECT d.name FROM sys.databases d
|
||||
WHERE d.state = 0 AND d.database_id > 4 AND HAS_DBACCESS(d.name) = 1
|
||||
AND NOT EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: IndexCollector.MissingSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.MissingSql
|
||||
SELECT DB_NAME(d.database_id), d.statement, d.equality_columns, d.inequality_columns, d.included_columns,
|
||||
gs.user_seeks, gs.user_scans, gs.avg_total_user_cost, gs.avg_user_impact, gs.last_user_seek
|
||||
FROM sys.dm_db_missing_index_details d
|
||||
JOIN sys.dm_db_missing_index_groups g ON g.index_handle = d.index_handle
|
||||
JOIN sys.dm_db_missing_index_group_stats gs ON gs.group_handle = g.index_group_handle
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildIndexSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildIndexSql(database, filteredIndexes: true)
|
||||
SELECT s.name, o.name, i.index_id, i.name, i.type_desc, i.is_unique, i.is_primary_key, i.is_unique_constraint, i.is_disabled,
|
||||
i.filter_definition,
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0
|
||||
AND ic.key_ordinal > 0
|
||||
ORDER BY ic.key_ordinal
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1
|
||||
|
||||
ORDER BY c.name
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
ps.row_count, ps.used_pages,
|
||||
us.user_seeks, us.user_scans, us.user_lookups, us.user_updates,
|
||||
fw.forwarded
|
||||
FROM [msdb].sys.indexes i
|
||||
JOIN [msdb].sys.objects o ON o.object_id = i.object_id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
OUTER APPLY (SELECT SUM(p.row_count) AS row_count, SUM(p.used_page_count) AS used_pages
|
||||
FROM [msdb].sys.dm_db_partition_stats p WHERE p.object_id = i.object_id AND p.index_id = i.index_id) ps
|
||||
LEFT JOIN sys.dm_db_index_usage_stats us ON us.database_id = DB_ID(N'msdb') AND us.object_id = i.object_id AND us.index_id = i.index_id
|
||||
OUTER APPLY (SELECT SUM(os.forwarded_fetch_count) AS forwarded
|
||||
FROM sys.dm_db_index_operational_stats(DB_ID(N'msdb'), i.object_id, 0, NULL) os WHERE i.index_id = 0) fw;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildIndexSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildIndexSql(database, filteredIndexes: false)
|
||||
SELECT s.name, o.name, i.index_id, i.name, i.type_desc, i.is_unique, i.is_primary_key, i.is_unique_constraint, i.is_disabled,
|
||||
CAST(NULL AS nvarchar(max)),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0
|
||||
AND ic.key_ordinal > 0
|
||||
ORDER BY ic.key_ordinal
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
STUFF((SELECT NCHAR(57344) + c.name + CASE WHEN ic.is_descending_key = 1 THEN N' DESC' ELSE N'' END
|
||||
FROM [msdb].sys.index_columns ic JOIN [msdb].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1
|
||||
|
||||
ORDER BY c.name
|
||||
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, N''),
|
||||
ps.row_count, ps.used_pages,
|
||||
us.user_seeks, us.user_scans, us.user_lookups, us.user_updates,
|
||||
fw.forwarded
|
||||
FROM [msdb].sys.indexes i
|
||||
JOIN [msdb].sys.objects o ON o.object_id = i.object_id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
OUTER APPLY (SELECT SUM(p.row_count) AS row_count, SUM(p.used_page_count) AS used_pages
|
||||
FROM [msdb].sys.dm_db_partition_stats p WHERE p.object_id = i.object_id AND p.index_id = i.index_id) ps
|
||||
LEFT JOIN sys.dm_db_index_usage_stats us ON us.database_id = DB_ID(N'msdb') AND us.object_id = i.object_id AND us.index_id = i.index_id
|
||||
OUTER APPLY (SELECT SUM(os.forwarded_fetch_count) AS forwarded
|
||||
FROM sys.dm_db_index_operational_stats(DB_ID(N'msdb'), i.object_id, 0, NULL) os WHERE i.index_id = 0) fw;
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere: én gang pr. database (vist for msdb)
|
||||
-- Kilde: IndexCollector.BuildStatisticsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/IndexCollector.cs : IndexCollector.BuildStatisticsSql(database)
|
||||
SELECT s.name, o.name, si.name, STATS_DATE(si.id, si.indid),
|
||||
COALESCE((SELECT TOP 1 t.rowcnt FROM [msdb].sys.sysindexes t WHERE t.id = si.id AND t.indid IN (0, 1)), si.rowcnt), si.rowmodctr
|
||||
FROM [msdb].sys.sysindexes si
|
||||
JOIN [msdb].sys.objects o ON o.object_id = si.id AND o.type = 'U' AND o.is_ms_shipped = 0
|
||||
JOIN [msdb].sys.schemas s ON s.schema_id = o.schema_id
|
||||
WHERE si.indid > 0 AND si.indid < 255;
|
||||
GO
|
||||
222
SQL Scripts/SQLI-STAT-002.sql
Normal file
222
SQL Scripts/SQLI-STAT-002.sql
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-STAT-002: Automatisk statistik er slået fra
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-STAT-002
|
||||
-- Titel: Automatisk statistik er slået fra
|
||||
-- Alvor: Medium
|
||||
-- Versioner: Alle (SQL Server 2000 via DATABASEPROPERTYEX).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om automatisk oprettelse eller opdatering af statistik er slået fra.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund pr. ONLINE, ikke read-only database, hvor is_auto_create_stats_on = 0 eller is_auto_update_stats_on = 0.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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];
|
||||
-- USE msdb; GRANT SELECT ON dbo.backupset TO [agent];
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- DatabaseCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs
|
||||
-- Medlemmer: DatabaseCollector.BuildSql2005(instance, capabilities), DatabaseCollector.BuildSql2000(),
|
||||
-- DatabaseCollector.Files2005, DatabaseCollector.Files2000, Db.UtcOffsetSql, DatabaseCollector.VlfSql,
|
||||
-- DatabaseCollector.BuildQueryStoreSql(database)
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:databases)
|
||||
-- Delt script: SQL Scripts/_collectors/DatabaseCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Indexes/IndexRules.cs : AutoStatisticsRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- DatabaseCollector: Databaseindstillinger og -tilstand, backup-historik (msdb), seneste fejlfri CHECKDB, VLF'er,
|
||||
-- Query Store-tilstand og filer.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2016 SP2+)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2012 – 2016 SP1
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2012)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
OR EXISTS (SELECT 1 FROM sys.dm_hadr_database_replica_states rs
|
||||
JOIN sys.dm_hadr_availability_replica_states ars ON ars.replica_id = rs.replica_id
|
||||
WHERE rs.database_id = d.database_id AND rs.is_local = 1 AND ars.role = 2)
|
||||
THEN 1 ELSE 0 END,
|
||||
CASE WHEN d.replica_id IS NOT NULL THEN 1 ELSE 0 END,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 – 2008 R2
|
||||
-- Kilde: DatabaseCollector.BuildSql2005(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2005(instance, capabilities)
|
||||
SELECT d.name, d.database_id, d.state_desc, d.recovery_model_desc, d.compatibility_level, d.page_verify_option_desc,
|
||||
d.is_auto_close_on, d.is_auto_shrink_on, d.is_read_only, d.is_trustworthy_on, d.create_date,
|
||||
CASE WHEN EXISTS (SELECT 1 FROM sys.database_mirroring m WHERE m.database_id = d.database_id AND m.mirroring_role = 2)
|
||||
|
||||
THEN 1 ELSE 0 END,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.create_date) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.create_date) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.create_date) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
d.is_auto_create_stats_on, d.is_auto_update_stats_on
|
||||
FROM sys.databases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.BuildSql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildSql2000()
|
||||
SELECT d.name, d.dbid,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Status') AS nvarchar(60)),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'Recovery') AS nvarchar(60)),
|
||||
d.cmptlevel,
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'IsTornPageDetectionEnabled') = 1 THEN N'TORN_PAGE_DETECTION' ELSE N'NONE' END,
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoClose') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoShrink') AS int),
|
||||
CASE WHEN DATABASEPROPERTYEX(d.name, 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END,
|
||||
0,
|
||||
d.crdate,
|
||||
0,
|
||||
0,
|
||||
CASE WHEN b.last_full >= DATEADD(second, -1, d.crdate) THEN b.last_full END,
|
||||
CASE WHEN b.last_diff >= DATEADD(second, -1, d.crdate) THEN b.last_diff END,
|
||||
CASE WHEN b.last_log >= DATEADD(second, -1, d.crdate) THEN b.last_log END,
|
||||
CAST(NULL AS datetime),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoCreateStatistics') AS int),
|
||||
CAST(DATABASEPROPERTYEX(d.name, 'IsAutoUpdateStatistics') AS int)
|
||||
FROM master.dbo.sysdatabases d
|
||||
LEFT JOIN (
|
||||
SELECT database_name,
|
||||
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
|
||||
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
|
||||
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log,
|
||||
MIN(backup_finish_date) AS first_backup
|
||||
FROM msdb.dbo.backupset
|
||||
GROUP BY database_name
|
||||
) b ON b.database_name = d.name
|
||||
WHERE d.name <> N'tempdb'
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: DatabaseCollector.Files2005
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2005
|
||||
SELECT database_id, name, type_desc, physical_name,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN is_percent_growth = 1 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
is_percent_growth,
|
||||
CASE WHEN max_size = -1 THEN -1 ELSE CAST(max_size AS bigint) / 128 END
|
||||
FROM sys.master_files
|
||||
WHERE type_desc IN (N'ROWS', N'LOG')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: DatabaseCollector.Files2000
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.Files2000
|
||||
SELECT dbid, name, CASE WHEN groupid = 0 THEN N'LOG' ELSE N'ROWS' END, filename,
|
||||
CAST(size AS bigint) / 128,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN growth ELSE CAST(growth AS bigint) / 128 END,
|
||||
CASE WHEN status & 0x100000 <> 0 THEN 1 ELSE 0 END,
|
||||
CASE WHEN maxsize = -1 THEN -1 ELSE CAST(maxsize AS bigint) / 128 END
|
||||
FROM master.dbo.sysaltfiles
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)
|
||||
-- Kilde: Db.UtcOffsetSql
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.UtcOffsetSql
|
||||
SELECT DATEDIFF(minute, GETUTCDATE(), GETDATE())
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)
|
||||
-- Kilde: DatabaseCollector.VlfSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.VlfSql
|
||||
SELECT d.database_id, COUNT(*)
|
||||
FROM sys.databases d
|
||||
CROSS APPLY sys.dm_db_log_info(d.database_id) li
|
||||
WHERE d.state = 0
|
||||
GROUP BY d.database_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for msdb)
|
||||
-- Kilde: DatabaseCollector.BuildQueryStoreSql
|
||||
-- Kode: src/SQLInsight.Collectors/Databases/DatabaseCollector.cs : DatabaseCollector.BuildQueryStoreSql(database)
|
||||
SELECT desired_state_desc, actual_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb
|
||||
FROM [msdb].sys.database_query_store_options
|
||||
GO
|
||||
118
SQL Scripts/SQLI-SVC-001.sql
Normal file
118
SQL Scripts/SQLI-SVC-001.sql
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-SVC-001: En SQL Server-tjeneste, der skal starte automatisk, kører ikke
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-SVC-001
|
||||
-- Titel: En SQL Server-tjeneste, der skal starte automatisk, kører ikke
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2008 R2 SP1 og nyere (sys.dm_server_services).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en SQL Server-tjeneste (fx SQL Server Agent, Full-text launcher, Launchpad), der er sat til at starte
|
||||
-- automatisk, ikke kører.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ét fund pr. tjeneste i sys.dm_server_services med startup_type_desc = Automatic og status_desc <> Running. Kunne
|
||||
-- tjenesterne ikke læses: "ikke målbar".
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen.
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- InstanceConfigurationCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs
|
||||
-- Medlemmer: InstanceConfigurationCollector.PropertiesSql, InstanceConfigurationCollector.TempdbSql,
|
||||
-- InstanceConfigurationCollector.ColumnsSql, InstanceConfigurationCollector.BuildServicesSql(true),
|
||||
-- InstanceConfigurationCollector.BuildServicesSql(false), InstanceConfigurationCollector.MemoryModelSql
|
||||
-- Interval: 15 min som standard (SQLInsight:CollectorIntervals:instance-config)
|
||||
-- Delt script: SQL Scripts/_collectors/InstanceConfigurationCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Instance/ServiceRules.cs : StoppedServiceRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt DBCC TRACESTATUS (læser trace flags), SET-sessionsindstillinger. Intet ændrer
|
||||
-- data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- InstanceConfigurationCollector: Instansens opsætning til konfigurationssiden og ændringsloggen: egenskaber,
|
||||
-- tempdb-filer, tjenester og konti, Instant File Initialization, memory model, sp_configure og trace flags.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere (samme forespørgsel som ConfigurationCollector)
|
||||
-- Kilde: ConfigurationCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2005
|
||||
SELECT name, CAST(value AS bigint), CAST(value_in_use AS bigint) FROM sys.configurations
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti) (samme forespørgsel som ConfigurationCollector)
|
||||
-- Kilde: ConfigurationCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/ConfigurationCollector.cs : ConfigurationCollector.Sql2000
|
||||
SELECT v.name, CAST(c.value AS bigint), CAST(r.value AS bigint)
|
||||
FROM master.dbo.spt_values v
|
||||
JOIN master.dbo.sysconfigures c ON c.config = v.number
|
||||
JOIN master.dbo.syscurconfigs r ON r.config = v.number
|
||||
WHERE v.type = 'C'
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner (SQL Server 2000 og nyere) (samme forespørgsel som TraceFlagCollector)
|
||||
-- Kilde: TraceFlagCollector.Sql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TraceFlagCollector.cs : TraceFlagCollector.Sql
|
||||
DBCC TRACESTATUS(-1) WITH NO_INFOMSGS
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner
|
||||
-- Kilde: InstanceConfigurationCollector.PropertiesSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.PropertiesSql
|
||||
SELECT CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)), CAST(SERVERPROPERTY('ProductLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('Edition') AS nvarchar(128)), CAST(SERVERPROPERTY('Collation') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('InstanceDefaultDataPath') AS nvarchar(260)), CAST(SERVERPROPERTY('InstanceDefaultLogPath') AS nvarchar(260))
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: InstanceConfigurationCollector.TempdbSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.TempdbSql
|
||||
SELECT name, type_desc, CAST(size AS bigint) / 128, growth, is_percent_growth, max_size
|
||||
FROM sys.master_files WHERE database_id = 2 ORDER BY file_id
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og nyere
|
||||
-- Kilde: InstanceConfigurationCollector.ColumnsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.ColumnsSql
|
||||
SELECT COL_LENGTH('sys.dm_server_services', 'instant_file_initialization_enabled'), COL_LENGTH('sys.dm_os_sys_info', 'sql_memory_model_desc')
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og nyere, builds med kolonnen instant_file_initialization_enabled (se ColumnsSql)
|
||||
-- Kilde: InstanceConfigurationCollector.BuildServicesSql(med IFI)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.BuildServicesSql(true)
|
||||
SELECT servicename, service_account, startup_type_desc, status_desc, instant_file_initialization_enabled FROM sys.dm_server_services
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2008 R2 SP1 og nyere, builds uden kolonnen instant_file_initialization_enabled
|
||||
-- Kilde: InstanceConfigurationCollector.BuildServicesSql(uden IFI)
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.BuildServicesSql(false)
|
||||
SELECT servicename, service_account, startup_type_desc, status_desc, CAST(NULL AS nvarchar(1)) FROM sys.dm_server_services
|
||||
GO
|
||||
|
||||
-- Variant: Builds med kolonnen sql_memory_model_desc (se ColumnsSql)
|
||||
-- Kilde: InstanceConfigurationCollector.MemoryModelSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/InstanceConfigurationCollector.cs : InstanceConfigurationCollector.MemoryModelSql
|
||||
SELECT sql_memory_model_desc FROM sys.dm_os_sys_info
|
||||
GO
|
||||
105
SQL Scripts/SQLI-TEMP-001.sql
Normal file
105
SQL Scripts/SQLI-TEMP-001.sql
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-TEMP-001: Version store i tempdb er stor eller vokser
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-TEMP-001
|
||||
-- Titel: Version store i tempdb er stor eller vokser
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om version store i tempdb er stor eller vokser støt - typisk fordi en lang transaktion holder gamle
|
||||
-- rækkeversioner i live.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Version store-størrelse = tælleren 'Version Store Size (KB)' (ellers version_store_reserved_page_count x 8 KB).
|
||||
-- Fund hvis størrelsen >= grænsen, eller hvis den er vokset i hver af de seneste 6 målinger og samlet med mindst
|
||||
-- 256 MB. Over halvdelen af grænsen spørges sys.dm_tran_top_version_generators (højst én gang i timen), hvilke
|
||||
-- databaser der laver versionerne.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:Tempdb:VersionStoreMegabytes, standard 1024 (MB); vækst over 6 målinger og 256 MB
|
||||
-- (TempdbAnalysis.IsGrowing, fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- TempdbCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/TempdbCollector.cs
|
||||
-- Medlemmer: TempdbCollector.SpaceSql, TempdbCollector.SessionsSql, TempdbCollector.OldestSnapshotSql,
|
||||
-- TempdbCollector.GeneratorsSql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:tempdb)
|
||||
-- Delt script: SQL Scripts/_collectors/TempdbCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Instance/TempdbRules.cs : VersionStoreRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- TempdbCollector: tempdb: fri plads, version store, bruger- og interne objekter, de tungeste sessioner, ældste
|
||||
-- snapshot-transaktion og hvilke databaser der laver rækkeversioner.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: TempdbCollector.SpaceSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.SpaceSql
|
||||
SELECT SUM(CAST(u.unallocated_extent_page_count AS bigint)), SUM(CAST(u.version_store_reserved_page_count AS bigint)),
|
||||
SUM(CAST(u.user_object_reserved_page_count AS bigint)), SUM(CAST(u.internal_object_reserved_page_count AS bigint)),
|
||||
(SELECT SUM(CAST(f.size AS bigint)) FROM tempdb.sys.database_files f WHERE f.type = 0),
|
||||
(SELECT MAX(CASE WHEN f.growth > 0 AND (f.max_size = -1 OR f.size < f.max_size) THEN 1 ELSE 0 END) FROM tempdb.sys.database_files f WHERE f.type = 0),
|
||||
(SELECT MAX(CAST(p.cntr_value AS bigint)) FROM sys.dm_os_performance_counters p
|
||||
WHERE p.counter_name = N'Version Store Size (KB)' AND p.object_name LIKE N'%Transactions%')
|
||||
FROM tempdb.sys.dm_db_file_space_usage u
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: TempdbCollector.SessionsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.SessionsSql
|
||||
SELECT TOP 5 u.session_id, DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), s.login_time), u.pages, s.login_name, s.program_name, s.host_name, s.status
|
||||
FROM (SELECT a.session_id, SUM(a.uo_alloc - a.uo_dealloc + a.io_alloc - a.io_dealloc) AS pages
|
||||
FROM (SELECT session_id, CAST(user_objects_alloc_page_count AS bigint) AS uo_alloc, CAST(user_objects_dealloc_page_count AS bigint) AS uo_dealloc,
|
||||
CAST(internal_objects_alloc_page_count AS bigint) AS io_alloc, CAST(internal_objects_dealloc_page_count AS bigint) AS io_dealloc
|
||||
FROM sys.dm_db_session_space_usage
|
||||
UNION ALL
|
||||
SELECT session_id, CAST(user_objects_alloc_page_count AS bigint), CAST(user_objects_dealloc_page_count AS bigint),
|
||||
CAST(internal_objects_alloc_page_count AS bigint), CAST(internal_objects_dealloc_page_count AS bigint)
|
||||
FROM sys.dm_db_task_space_usage) a
|
||||
GROUP BY a.session_id) u
|
||||
JOIN sys.dm_exec_sessions s ON s.session_id = u.session_id
|
||||
WHERE s.is_user_process = 1 AND u.pages > 0
|
||||
ORDER BY u.pages DESC
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: TempdbCollector.OldestSnapshotSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.OldestSnapshotSql
|
||||
SELECT TOP 1 t.session_id, t.elapsed_time_seconds, s.login_name, s.program_name
|
||||
FROM sys.dm_tran_active_snapshot_database_transactions t
|
||||
LEFT JOIN sys.dm_exec_sessions s ON s.session_id = t.session_id
|
||||
ORDER BY t.elapsed_time_seconds DESC
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kun når version store er over halvdelen af grænsen, højst én gang i timen
|
||||
-- Kilde: TempdbCollector.GeneratorsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.GeneratorsSql
|
||||
SELECT TOP 10 DB_NAME(database_id), SUM(CAST(aggregated_record_length_in_bytes AS bigint))
|
||||
FROM sys.dm_tran_top_version_generators
|
||||
GROUP BY database_id
|
||||
ORDER BY SUM(CAST(aggregated_record_length_in_bytes AS bigint)) DESC
|
||||
GO
|
||||
101
SQL Scripts/SQLI-TEMP-002.sql
Normal file
101
SQL Scripts/SQLI-TEMP-002.sql
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-TEMP-002: tempdb er næsten fuld
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-TEMP-002
|
||||
-- Titel: tempdb er næsten fuld
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om tempdb er næsten fuld og ikke kan vokse, så sorteringer, temp-tabeller og version store snart fejler.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund hvis ingen af tempdb's datafiler kan vokse (growth > 0 og size < max_size eller max_size = -1) og fri plads
|
||||
-- (unallocated_extent_page_count) er under 10 % af datafilernes størrelse.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 10 % fri (TempdbFullRule.FreePercent, fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- TempdbCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/TempdbCollector.cs
|
||||
-- Medlemmer: TempdbCollector.SpaceSql, TempdbCollector.SessionsSql, TempdbCollector.OldestSnapshotSql,
|
||||
-- TempdbCollector.GeneratorsSql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:tempdb)
|
||||
-- Delt script: SQL Scripts/_collectors/TempdbCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Instance/TempdbRules.cs : TempdbFullRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- TempdbCollector: tempdb: fri plads, version store, bruger- og interne objekter, de tungeste sessioner, ældste
|
||||
-- snapshot-transaktion og hvilke databaser der laver rækkeversioner.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: TempdbCollector.SpaceSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.SpaceSql
|
||||
SELECT SUM(CAST(u.unallocated_extent_page_count AS bigint)), SUM(CAST(u.version_store_reserved_page_count AS bigint)),
|
||||
SUM(CAST(u.user_object_reserved_page_count AS bigint)), SUM(CAST(u.internal_object_reserved_page_count AS bigint)),
|
||||
(SELECT SUM(CAST(f.size AS bigint)) FROM tempdb.sys.database_files f WHERE f.type = 0),
|
||||
(SELECT MAX(CASE WHEN f.growth > 0 AND (f.max_size = -1 OR f.size < f.max_size) THEN 1 ELSE 0 END) FROM tempdb.sys.database_files f WHERE f.type = 0),
|
||||
(SELECT MAX(CAST(p.cntr_value AS bigint)) FROM sys.dm_os_performance_counters p
|
||||
WHERE p.counter_name = N'Version Store Size (KB)' AND p.object_name LIKE N'%Transactions%')
|
||||
FROM tempdb.sys.dm_db_file_space_usage u
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: TempdbCollector.SessionsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.SessionsSql
|
||||
SELECT TOP 5 u.session_id, DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), s.login_time), u.pages, s.login_name, s.program_name, s.host_name, s.status
|
||||
FROM (SELECT a.session_id, SUM(a.uo_alloc - a.uo_dealloc + a.io_alloc - a.io_dealloc) AS pages
|
||||
FROM (SELECT session_id, CAST(user_objects_alloc_page_count AS bigint) AS uo_alloc, CAST(user_objects_dealloc_page_count AS bigint) AS uo_dealloc,
|
||||
CAST(internal_objects_alloc_page_count AS bigint) AS io_alloc, CAST(internal_objects_dealloc_page_count AS bigint) AS io_dealloc
|
||||
FROM sys.dm_db_session_space_usage
|
||||
UNION ALL
|
||||
SELECT session_id, CAST(user_objects_alloc_page_count AS bigint), CAST(user_objects_dealloc_page_count AS bigint),
|
||||
CAST(internal_objects_alloc_page_count AS bigint), CAST(internal_objects_dealloc_page_count AS bigint)
|
||||
FROM sys.dm_db_task_space_usage) a
|
||||
GROUP BY a.session_id) u
|
||||
JOIN sys.dm_exec_sessions s ON s.session_id = u.session_id
|
||||
WHERE s.is_user_process = 1 AND u.pages > 0
|
||||
ORDER BY u.pages DESC
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: TempdbCollector.OldestSnapshotSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.OldestSnapshotSql
|
||||
SELECT TOP 1 t.session_id, t.elapsed_time_seconds, s.login_name, s.program_name
|
||||
FROM sys.dm_tran_active_snapshot_database_transactions t
|
||||
LEFT JOIN sys.dm_exec_sessions s ON s.session_id = t.session_id
|
||||
ORDER BY t.elapsed_time_seconds DESC
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kun når version store er over halvdelen af grænsen, højst én gang i timen
|
||||
-- Kilde: TempdbCollector.GeneratorsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.GeneratorsSql
|
||||
SELECT TOP 10 DB_NAME(database_id), SUM(CAST(aggregated_record_length_in_bytes AS bigint))
|
||||
FROM sys.dm_tran_top_version_generators
|
||||
GROUP BY database_id
|
||||
ORDER BY SUM(CAST(aggregated_record_length_in_bytes AS bigint)) DESC
|
||||
GO
|
||||
103
SQL Scripts/SQLI-TEMP-003.sql
Normal file
103
SQL Scripts/SQLI-TEMP-003.sql
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-TEMP-003: Session bruger meget tempdb i lang tid
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-TEMP-003
|
||||
-- Titel: Session bruger meget tempdb i lang tid
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en session har brugt meget tempdb i lang tid.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- SQL'en finder de 5 brugersessioner, der bruger mest tempdb (bruger- + interne objekter, allokeret - deallokeret,
|
||||
-- fra session- og task-space-usage). C# husker, hvornår hver session (session_id + login_time) første gang var over
|
||||
-- grænsen; fund når den har været over i mindst 15 minutter.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:Tempdb:SessionMegabytes, standard 1024 (MB); 15 minutter (TempdbAnalysis.HeavySessionMinutes, fast i
|
||||
-- koden).
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- TempdbCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Instance/TempdbCollector.cs
|
||||
-- Medlemmer: TempdbCollector.SpaceSql, TempdbCollector.SessionsSql, TempdbCollector.OldestSnapshotSql,
|
||||
-- TempdbCollector.GeneratorsSql
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:tempdb)
|
||||
-- Delt script: SQL Scripts/_collectors/TempdbCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Instance/TempdbRules.cs : TempdbSessionRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- TempdbCollector: tempdb: fri plads, version store, bruger- og interne objekter, de tungeste sessioner, ældste
|
||||
-- snapshot-transaktion og hvilke databaser der laver rækkeversioner.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: TempdbCollector.SpaceSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.SpaceSql
|
||||
SELECT SUM(CAST(u.unallocated_extent_page_count AS bigint)), SUM(CAST(u.version_store_reserved_page_count AS bigint)),
|
||||
SUM(CAST(u.user_object_reserved_page_count AS bigint)), SUM(CAST(u.internal_object_reserved_page_count AS bigint)),
|
||||
(SELECT SUM(CAST(f.size AS bigint)) FROM tempdb.sys.database_files f WHERE f.type = 0),
|
||||
(SELECT MAX(CASE WHEN f.growth > 0 AND (f.max_size = -1 OR f.size < f.max_size) THEN 1 ELSE 0 END) FROM tempdb.sys.database_files f WHERE f.type = 0),
|
||||
(SELECT MAX(CAST(p.cntr_value AS bigint)) FROM sys.dm_os_performance_counters p
|
||||
WHERE p.counter_name = N'Version Store Size (KB)' AND p.object_name LIKE N'%Transactions%')
|
||||
FROM tempdb.sys.dm_db_file_space_usage u
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: TempdbCollector.SessionsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.SessionsSql
|
||||
SELECT TOP 5 u.session_id, DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), s.login_time), u.pages, s.login_name, s.program_name, s.host_name, s.status
|
||||
FROM (SELECT a.session_id, SUM(a.uo_alloc - a.uo_dealloc + a.io_alloc - a.io_dealloc) AS pages
|
||||
FROM (SELECT session_id, CAST(user_objects_alloc_page_count AS bigint) AS uo_alloc, CAST(user_objects_dealloc_page_count AS bigint) AS uo_dealloc,
|
||||
CAST(internal_objects_alloc_page_count AS bigint) AS io_alloc, CAST(internal_objects_dealloc_page_count AS bigint) AS io_dealloc
|
||||
FROM sys.dm_db_session_space_usage
|
||||
UNION ALL
|
||||
SELECT session_id, CAST(user_objects_alloc_page_count AS bigint), CAST(user_objects_dealloc_page_count AS bigint),
|
||||
CAST(internal_objects_alloc_page_count AS bigint), CAST(internal_objects_dealloc_page_count AS bigint)
|
||||
FROM sys.dm_db_task_space_usage) a
|
||||
GROUP BY a.session_id) u
|
||||
JOIN sys.dm_exec_sessions s ON s.session_id = u.session_id
|
||||
WHERE s.is_user_process = 1 AND u.pages > 0
|
||||
ORDER BY u.pages DESC
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: TempdbCollector.OldestSnapshotSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.OldestSnapshotSql
|
||||
SELECT TOP 1 t.session_id, t.elapsed_time_seconds, s.login_name, s.program_name
|
||||
FROM sys.dm_tran_active_snapshot_database_transactions t
|
||||
LEFT JOIN sys.dm_exec_sessions s ON s.session_id = t.session_id
|
||||
ORDER BY t.elapsed_time_seconds DESC
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere, kun når version store er over halvdelen af grænsen, højst én gang i timen
|
||||
-- Kilde: TempdbCollector.GeneratorsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Instance/TempdbCollector.cs : TempdbCollector.GeneratorsSql
|
||||
SELECT TOP 10 DB_NAME(database_id), SUM(CAST(aggregated_record_length_in_bytes AS bigint))
|
||||
FROM sys.dm_tran_top_version_generators
|
||||
GROUP BY database_id
|
||||
ORDER BY SUM(CAST(aggregated_record_length_in_bytes AS bigint)) DESC
|
||||
GO
|
||||
92
SQL Scripts/SQLI-TRAN-001.sql
Normal file
92
SQL Scripts/SQLI-TRAN-001.sql
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-TRAN-001: Transaktion har været åben længe
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-TRAN-001
|
||||
-- Titel: Transaktion har været åben længe
|
||||
-- Alvor: Medium; High når den har været åben 6 x grænsen.
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en brugertransaktion har været åben længe og holder låse og forhindrer, at loggen og version store ryddes.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Hvert minut læses op til 100 åbne transaktioner for brugersessioner (ikke agentens egne). Fund (op til 10, ældste
|
||||
-- først) for transaktioner, hvis alder (målingstidspunkt - transaction_begin_time i UTC) er mindst grænsen.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:Activity:TransactionMinutes, standard 10 (minutter); High fra 6 x grænsen.
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ActivityCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Concurrency/ActivityCollector.cs
|
||||
-- Medlemmer: ActivityCollector.BuildTransactionsSql(1024) = TransactionsSql udfyldt,
|
||||
-- ActivityCollector.BuildLongRequestsSql(15) = LongRequestsSql udfyldt
|
||||
-- Interval: 1 min som standard (SQLInsight:CollectorIntervals:activity)
|
||||
-- Delt script: SQL Scripts/_collectors/ActivityCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Concurrency/ActivityRules.cs : LongTransactionRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ActivityCollector: Åbne brugertransaktioner (alder, log) og brugersætninger, der har kørt længere end grænsen.
|
||||
-- Agentens egne sessioner er udeladt.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere (vist med standardgrænsen 1024 MB log)
|
||||
-- Kilde: ActivityCollector.BuildTransactionsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Concurrency/ActivityCollector.cs : ActivityCollector.BuildTransactionsSql(1024) = TransactionsSql udfyldt
|
||||
SELECT TOP 100 t.session_id, t.transaction_id, t.name, DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), t.begin_time),
|
||||
t.used, t.reserved, t.db, t.dbs, s.login_name, s.host_name, s.program_name, s.status, r.wait_type,
|
||||
CAST(CASE WHEN r.sql_handle IS NOT NULL
|
||||
THEN SUBSTRING(q.text, r.statement_start_offset / 2 + 1,
|
||||
CASE WHEN r.statement_end_offset = -1 THEN 1000 ELSE (r.statement_end_offset - r.statement_start_offset) / 2 + 1 END)
|
||||
ELSE LEFT(q.text, 1000) END AS nvarchar(1000))
|
||||
FROM (SELECT st.session_id, at.transaction_id, MAX(at.name) AS name, MIN(at.transaction_begin_time) AS begin_time,
|
||||
ISNULL(SUM(dt.database_transaction_log_bytes_used), 0) AS used, ISNULL(SUM(dt.database_transaction_log_bytes_reserved), 0) AS reserved,
|
||||
MIN(DB_NAME(dt.database_id)) AS db, COUNT(DISTINCT dt.database_id) AS dbs
|
||||
FROM sys.dm_tran_session_transactions st
|
||||
JOIN sys.dm_tran_active_transactions at ON at.transaction_id = st.transaction_id
|
||||
LEFT JOIN sys.dm_tran_database_transactions dt ON dt.transaction_id = st.transaction_id AND dt.database_id <> 32767
|
||||
GROUP BY st.session_id, at.transaction_id) t
|
||||
JOIN sys.dm_exec_sessions s ON s.session_id = t.session_id
|
||||
OUTER APPLY (SELECT TOP 1 x.sql_handle, x.statement_start_offset, x.statement_end_offset, x.wait_type FROM sys.dm_exec_requests x
|
||||
WHERE x.session_id = t.session_id ORDER BY x.request_id) r
|
||||
OUTER APPLY (SELECT TOP 1 c.most_recent_sql_handle FROM sys.dm_exec_connections c WHERE c.session_id = t.session_id) c
|
||||
OUTER APPLY sys.dm_exec_sql_text(COALESCE(r.sql_handle, c.most_recent_sql_handle)) q
|
||||
WHERE s.is_user_process = 1 AND s.session_id <> @@SPID AND (s.program_name IS NULL OR s.program_name NOT LIKE N'SQLInsight Pro%') AND t.begin_time IS NOT NULL
|
||||
ORDER BY CASE WHEN t.used + t.reserved >= 1073741824 THEN 0 ELSE 1 END, t.begin_time
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere (vist med standardgrænsen 15 minutter)
|
||||
-- Kilde: ActivityCollector.BuildLongRequestsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Concurrency/ActivityCollector.cs : ActivityCollector.BuildLongRequestsSql(15) = LongRequestsSql udfyldt
|
||||
SELECT TOP 50 r.session_id, DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), r.start_time), r.total_elapsed_time, r.command, r.status,
|
||||
r.wait_type, r.wait_time, DB_NAME(r.database_id), s.login_name, s.host_name, s.program_name, r.blocking_session_id,
|
||||
CAST(SUBSTRING(q.text, r.statement_start_offset / 2 + 1,
|
||||
CASE WHEN r.statement_end_offset = -1 THEN 1000 ELSE (r.statement_end_offset - r.statement_start_offset) / 2 + 1 END) AS nvarchar(1000))
|
||||
FROM sys.dm_exec_requests r
|
||||
JOIN sys.dm_exec_sessions s ON s.session_id = r.session_id
|
||||
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) q
|
||||
WHERE s.is_user_process = 1 AND s.session_id <> @@SPID AND (s.program_name IS NULL OR s.program_name NOT LIKE N'SQLInsight Pro%') AND r.total_elapsed_time > 900000 AND r.percent_complete = 0
|
||||
ORDER BY r.total_elapsed_time DESC
|
||||
GO
|
||||
93
SQL Scripts/SQLI-TRAN-002.sql
Normal file
93
SQL Scripts/SQLI-TRAN-002.sql
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-TRAN-002: Transaktion bruger meget transaktionslog
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-TRAN-002
|
||||
-- Titel: Transaktion bruger meget transaktionslog
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om en transaktion holder meget transaktionslog, som først kan frigives, når den afsluttes.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund (op til 10, største først) for transaktioner, hvor database_transaction_log_bytes_used + _reserved (summeret
|
||||
-- over databaser) er mindst grænsen. Grænsen indgår også i SQL'en: transaktioner over grænsen sorteres først, så de
|
||||
-- altid er blandt de 100 rækker.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:Activity:TransactionLogMegabytes, standard 1024 (MB) = 1073741824 bytes i SQL'en.
|
||||
--
|
||||
-- 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+
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- ActivityCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Concurrency/ActivityCollector.cs
|
||||
-- Medlemmer: ActivityCollector.BuildTransactionsSql(1024) = TransactionsSql udfyldt,
|
||||
-- ActivityCollector.BuildLongRequestsSql(15) = LongRequestsSql udfyldt
|
||||
-- Interval: 1 min som standard (SQLInsight:CollectorIntervals:activity)
|
||||
-- Delt script: SQL Scripts/_collectors/ActivityCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Concurrency/ActivityRules.cs : LargeTransactionRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- ActivityCollector: Åbne brugertransaktioner (alder, log) og brugersætninger, der har kørt længere end grænsen.
|
||||
-- Agentens egne sessioner er udeladt.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere (vist med standardgrænsen 1024 MB log)
|
||||
-- Kilde: ActivityCollector.BuildTransactionsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Concurrency/ActivityCollector.cs : ActivityCollector.BuildTransactionsSql(1024) = TransactionsSql udfyldt
|
||||
SELECT TOP 100 t.session_id, t.transaction_id, t.name, DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), t.begin_time),
|
||||
t.used, t.reserved, t.db, t.dbs, s.login_name, s.host_name, s.program_name, s.status, r.wait_type,
|
||||
CAST(CASE WHEN r.sql_handle IS NOT NULL
|
||||
THEN SUBSTRING(q.text, r.statement_start_offset / 2 + 1,
|
||||
CASE WHEN r.statement_end_offset = -1 THEN 1000 ELSE (r.statement_end_offset - r.statement_start_offset) / 2 + 1 END)
|
||||
ELSE LEFT(q.text, 1000) END AS nvarchar(1000))
|
||||
FROM (SELECT st.session_id, at.transaction_id, MAX(at.name) AS name, MIN(at.transaction_begin_time) AS begin_time,
|
||||
ISNULL(SUM(dt.database_transaction_log_bytes_used), 0) AS used, ISNULL(SUM(dt.database_transaction_log_bytes_reserved), 0) AS reserved,
|
||||
MIN(DB_NAME(dt.database_id)) AS db, COUNT(DISTINCT dt.database_id) AS dbs
|
||||
FROM sys.dm_tran_session_transactions st
|
||||
JOIN sys.dm_tran_active_transactions at ON at.transaction_id = st.transaction_id
|
||||
LEFT JOIN sys.dm_tran_database_transactions dt ON dt.transaction_id = st.transaction_id AND dt.database_id <> 32767
|
||||
GROUP BY st.session_id, at.transaction_id) t
|
||||
JOIN sys.dm_exec_sessions s ON s.session_id = t.session_id
|
||||
OUTER APPLY (SELECT TOP 1 x.sql_handle, x.statement_start_offset, x.statement_end_offset, x.wait_type FROM sys.dm_exec_requests x
|
||||
WHERE x.session_id = t.session_id ORDER BY x.request_id) r
|
||||
OUTER APPLY (SELECT TOP 1 c.most_recent_sql_handle FROM sys.dm_exec_connections c WHERE c.session_id = t.session_id) c
|
||||
OUTER APPLY sys.dm_exec_sql_text(COALESCE(r.sql_handle, c.most_recent_sql_handle)) q
|
||||
WHERE s.is_user_process = 1 AND s.session_id <> @@SPID AND (s.program_name IS NULL OR s.program_name NOT LIKE N'SQLInsight Pro%') AND t.begin_time IS NOT NULL
|
||||
ORDER BY CASE WHEN t.used + t.reserved >= 1073741824 THEN 0 ELSE 1 END, t.begin_time
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere (vist med standardgrænsen 15 minutter)
|
||||
-- Kilde: ActivityCollector.BuildLongRequestsSql
|
||||
-- Kode: src/SQLInsight.Collectors/Concurrency/ActivityCollector.cs : ActivityCollector.BuildLongRequestsSql(15) = LongRequestsSql udfyldt
|
||||
SELECT TOP 50 r.session_id, DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), r.start_time), r.total_elapsed_time, r.command, r.status,
|
||||
r.wait_type, r.wait_time, DB_NAME(r.database_id), s.login_name, s.host_name, s.program_name, r.blocking_session_id,
|
||||
CAST(SUBSTRING(q.text, r.statement_start_offset / 2 + 1,
|
||||
CASE WHEN r.statement_end_offset = -1 THEN 1000 ELSE (r.statement_end_offset - r.statement_start_offset) / 2 + 1 END) AS nvarchar(1000))
|
||||
FROM sys.dm_exec_requests r
|
||||
JOIN sys.dm_exec_sessions s ON s.session_id = r.session_id
|
||||
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) q
|
||||
WHERE s.is_user_process = 1 AND s.session_id <> @@SPID AND (s.program_name IS NULL OR s.program_name NOT LIKE N'SQLInsight Pro%') AND r.total_elapsed_time > 900000 AND r.percent_complete = 0
|
||||
ORDER BY r.total_elapsed_time DESC
|
||||
GO
|
||||
71
SQL Scripts/SQLI-VER-001.sql
Normal file
71
SQL Scripts/SQLI-VER-001.sql
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-VER-001: SQL Server-versionens supportstatus
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-VER-001
|
||||
-- Titel: SQL Server-versionens supportstatus
|
||||
-- Alvor: Critical når extended support er udløbet; High når mainstream er udløbet og der er højst 365 dage til
|
||||
-- extended support slutter; ellers Medium i extended support.
|
||||
-- Versioner: Alle (SQL Server 2000 og nyere). Ikke relevant på Azure SQL Managed Instance (kræver
|
||||
-- SelfManagedInfrastructure: Azure patcher selv).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om instansens SQL Server-udgivelse er ude af, eller på vej ud af, Microsofts support. En version uden support får
|
||||
-- ingen sikkerhedsopdateringer.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Udgivelsen (fx SQL Server 2016) udledes af ProductVersion fra InstanceProbe. Datoerne for mainstream og extended
|
||||
-- support slås op i regelpakken (src/SQLInsight.Rules/Lifecycle/support-lifecycle.json eller en nyere, downloadet
|
||||
-- regelpakke). Dagens dato (UTC) > extended end: Critical. Dagens dato > mainstream end: High, hvis der er højst
|
||||
-- 365 dage til extended end, ellers Medium. Ukendt version eller manglende datoer: "ikke målbar". Ingen SQL
|
||||
-- beregner selve dommen.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Advarselsvindue før extended end: 365 dage (SupportLifecycleRule.ExtendedEndWarningWindow, fast i koden, ingen
|
||||
-- konfigurationsnøgle).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- Ingen ekstra rettighed: public må læse dette (SERVERPROPERTY, sys.configurations, DBCC TRACESTATUS, xp_msver).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- InstanceProbe
|
||||
-- Fil: src/SQLInsight.Connectivity/InstanceProbe.cs
|
||||
-- Medlemmer: InstanceProbe.Query
|
||||
-- Interval: én gang, når agenten forbinder til instansen
|
||||
-- Delt script: SQL Scripts/_collectors/InstanceProbe.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Lifecycle/SupportLifecycleRule.cs : SupportLifecycleRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- InstanceProbe: Registrering af instansen: version, udgave, cluster og Always On. Køres, når agenten forbinder, og
|
||||
-- bestemmer hvilke varianter og regler der bruges.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner (SQL Server 2000 og nyere)
|
||||
-- Kilde: InstanceProbe.Query
|
||||
-- Kode: src/SQLInsight.Connectivity/InstanceProbe.cs : InstanceProbe.Query
|
||||
SELECT
|
||||
CAST(SERVERPROPERTY('ServerName') AS nvarchar(256)),
|
||||
CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductUpdateLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('Edition') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('EngineEdition') AS int),
|
||||
CAST(SERVERPROPERTY('IsClustered') AS int),
|
||||
CAST(SERVERPROPERTY('IsHadrEnabled') AS int)
|
||||
GO
|
||||
68
SQL Scripts/SQLI-VER-002.sql
Normal file
68
SQL Scripts/SQLI-VER-002.sql
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-VER-002: Instansen mangler opdateringer
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-VER-002
|
||||
-- Titel: Instansen mangler opdateringer
|
||||
-- Alvor: High når versionen stadig er i support; Medium når den er ude af support (så er SQLI-VER-001 det
|
||||
-- vigtigste fund).
|
||||
-- Versioner: Alle (SQL Server 2000 og nyere). Ikke relevant på Azure SQL Managed Instance.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om instansen mangler den seneste kendte cumulative update, sikkerhedsopdatering eller service pack for sin
|
||||
-- udgivelse.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- ProductVersion (InstanceProbe) sammenlignes med det nyeste build for udgivelsen i regelpakkens build-katalog
|
||||
-- (src/SQLInsight.Rules/Lifecycle/build-catalog.json eller downloadet regelpakke). Lavere build: fund. Er kataloget
|
||||
-- ældre end 120 dage, står det i målingerne, at det kan være forældet. Kender kataloget ikke udgivelsen: "ikke
|
||||
-- målbar".
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Katalogets maksimale alder før advarsel: 120 dage (PatchLevelRule.CatalogMaxAge, fast i koden).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql; [agent] = agentens login):
|
||||
-- Ingen ekstra rettighed: public må læse dette (SERVERPROPERTY, sys.configurations, DBCC TRACESTATUS, xp_msver).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- InstanceProbe
|
||||
-- Fil: src/SQLInsight.Connectivity/InstanceProbe.cs
|
||||
-- Medlemmer: InstanceProbe.Query
|
||||
-- Interval: én gang, når agenten forbinder til instansen
|
||||
-- Delt script: SQL Scripts/_collectors/InstanceProbe.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Lifecycle/PatchLevelRule.cs : PatchLevelRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- InstanceProbe: Registrering af instansen: version, udgave, cluster og Always On. Køres, når agenten forbinder, og
|
||||
-- bestemmer hvilke varianter og regler der bruges.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner (SQL Server 2000 og nyere)
|
||||
-- Kilde: InstanceProbe.Query
|
||||
-- Kode: src/SQLInsight.Connectivity/InstanceProbe.cs : InstanceProbe.Query
|
||||
SELECT
|
||||
CAST(SERVERPROPERTY('ServerName') AS nvarchar(256)),
|
||||
CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('ProductUpdateLevel') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('Edition') AS nvarchar(128)),
|
||||
CAST(SERVERPROPERTY('EngineEdition') AS int),
|
||||
CAST(SERVERPROPERTY('IsClustered') AS int),
|
||||
CAST(SERVERPROPERTY('IsHadrEnabled') AS int)
|
||||
GO
|
||||
87
SQL Scripts/SQLI-WAIT-001.sql
Normal file
87
SQL Scripts/SQLI-WAIT-001.sql
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-WAIT-001: SQL Server løber tør for worker threads
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WAIT-001
|
||||
-- Titel: SQL Server løber tør for worker threads
|
||||
-- Alvor: Critical
|
||||
-- Versioner: Alle (SQL Server 2000 via DBCC SQLPERF(WAITSTATS)).
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om SQL Server er løbet tør for worker threads (THREADPOOL-ventetider): nye forbindelser hænger.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Ventetiderne er kumulative; reglen bruger forskellen mellem to målinger (normalt 5 minutter; nulstilles ved
|
||||
-- genstart, hvor første måling ikke giver noget fund). Godartede/idle ventetyper fjernes (WaitCatalog.IsBenign).
|
||||
-- Fund hvis THREADPOOL har ventet mindst 1.000 ms i intervallet.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 1.000 ms i intervallet (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- WaitStatsCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), WaitStatsCollector.Sql2005, WaitStatsCollector.Sql2000
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:wait-stats)
|
||||
-- Delt script: SQL Scripts/_collectors/WaitStatsCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/WaitRules.cs : ThreadPoolWaitRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt DBCC SQLPERF(WAITSTATS) (læser ventetider, SQL Server 2000),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- WaitStatsCollector: Kumulative ventetider. Reglerne bruger forskellen mellem to målinger; en genstart (nyt
|
||||
-- starttidspunkt) nulstiller.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt (nulstilling af kumulative tal)
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: WaitStatsCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2005
|
||||
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
|
||||
FROM sys.dm_os_wait_stats
|
||||
WHERE wait_time_ms > 0
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: WaitStatsCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2000
|
||||
DBCC SQLPERF(WAITSTATS) WITH NO_INFOMSGS
|
||||
GO
|
||||
87
SQL Scripts/SQLI-WAIT-002.sql
Normal file
87
SQL Scripts/SQLI-WAIT-002.sql
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-WAIT-002: Tasks venter på CPU (høj signal wait)
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WAIT-002
|
||||
-- Titel: Tasks venter på CPU (høj signal wait)
|
||||
-- Alvor: Medium; High fra 40 %.
|
||||
-- Versioner: Alle.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om tasks venter på CPU (høj andel signal wait), dvs. schedulers er overbelastede.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Forskellen mellem to målinger, uden godartede ventetyper. Fund hvis summen af signal_wait_time_ms / summen af
|
||||
-- wait_time_ms >= 25 %, og der i gennemsnit er mindst én ventende task (samlet ventetid / intervallets længde >=
|
||||
-- 1).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 25 %; High fra 40 %; mindst 1 ventende task i gennemsnit (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- WaitStatsCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), WaitStatsCollector.Sql2005, WaitStatsCollector.Sql2000
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:wait-stats)
|
||||
-- Delt script: SQL Scripts/_collectors/WaitStatsCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/WaitRules.cs : SignalWaitRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt DBCC SQLPERF(WAITSTATS) (læser ventetider, SQL Server 2000),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- WaitStatsCollector: Kumulative ventetider. Reglerne bruger forskellen mellem to målinger; en genstart (nyt
|
||||
-- starttidspunkt) nulstiller.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt (nulstilling af kumulative tal)
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: WaitStatsCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2005
|
||||
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
|
||||
FROM sys.dm_os_wait_stats
|
||||
WHERE wait_time_ms > 0
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: WaitStatsCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2000
|
||||
DBCC SQLPERF(WAITSTATS) WITH NO_INFOMSGS
|
||||
GO
|
||||
87
SQL Scripts/SQLI-WAIT-003.sql
Normal file
87
SQL Scripts/SQLI-WAIT-003.sql
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-WAIT-003: Sessioner venter meget på låse
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WAIT-003
|
||||
-- Titel: Sessioner venter meget på låse
|
||||
-- Alvor: Medium; High fra 5 ventende tasks i gennemsnit.
|
||||
-- Versioner: Alle.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om sessioner venter meget på låse (LCK_M_*), dvs. blocking.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Forskellen mellem to målinger, uden godartede ventetyper. Fund hvis LCK_M_* udgør mindst 20 % af al ventetid og i
|
||||
-- gennemsnit mindst 0,5 task venter på låse (ventetid / intervallets længde).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Andel >= 20 %, gns. ventende >= 0,5; High fra 5 (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- WaitStatsCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), WaitStatsCollector.Sql2005, WaitStatsCollector.Sql2000
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:wait-stats)
|
||||
-- Delt script: SQL Scripts/_collectors/WaitStatsCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/WaitRules.cs : WaitRules.Create (DominantWaitRule "SQLI-WAIT-003",
|
||||
-- kategori Locks)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt DBCC SQLPERF(WAITSTATS) (læser ventetider, SQL Server 2000),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- WaitStatsCollector: Kumulative ventetider. Reglerne bruger forskellen mellem to målinger; en genstart (nyt
|
||||
-- starttidspunkt) nulstiller.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt (nulstilling af kumulative tal)
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: WaitStatsCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2005
|
||||
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
|
||||
FROM sys.dm_os_wait_stats
|
||||
WHERE wait_time_ms > 0
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: WaitStatsCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2000
|
||||
DBCC SQLPERF(WAITSTATS) WITH NO_INFOMSGS
|
||||
GO
|
||||
87
SQL Scripts/SQLI-WAIT-004.sql
Normal file
87
SQL Scripts/SQLI-WAIT-004.sql
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-WAIT-004: Forespørgsler venter meget på at læse data fra disk
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WAIT-004
|
||||
-- Titel: Forespørgsler venter meget på at læse data fra disk
|
||||
-- Alvor: Medium; High fra 8 ventende tasks i gennemsnit.
|
||||
-- Versioner: Alle.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om forespørgsler venter meget på at læse sider fra disk (PAGEIOLATCH_*).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Forskellen mellem to målinger, uden godartede ventetyper. Fund hvis PAGEIOLATCH_* udgør mindst 30 % af al
|
||||
-- ventetid og i gennemsnit mindst 1 task venter.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Andel >= 30 %, gns. ventende >= 1; High fra 8 (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- WaitStatsCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), WaitStatsCollector.Sql2005, WaitStatsCollector.Sql2000
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:wait-stats)
|
||||
-- Delt script: SQL Scripts/_collectors/WaitStatsCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/WaitRules.cs : WaitRules.Create (DominantWaitRule "SQLI-WAIT-004",
|
||||
-- kategori BufferIo)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt DBCC SQLPERF(WAITSTATS) (læser ventetider, SQL Server 2000),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- WaitStatsCollector: Kumulative ventetider. Reglerne bruger forskellen mellem to målinger; en genstart (nyt
|
||||
-- starttidspunkt) nulstiller.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt (nulstilling af kumulative tal)
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: WaitStatsCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2005
|
||||
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
|
||||
FROM sys.dm_os_wait_stats
|
||||
WHERE wait_time_ms > 0
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: WaitStatsCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2000
|
||||
DBCC SQLPERF(WAITSTATS) WITH NO_INFOMSGS
|
||||
GO
|
||||
86
SQL Scripts/SQLI-WAIT-005.sql
Normal file
86
SQL Scripts/SQLI-WAIT-005.sql
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-WAIT-005: Commits venter på langsom skrivning til transaktionsloggen
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WAIT-005
|
||||
-- Titel: Commits venter på langsom skrivning til transaktionsloggen
|
||||
-- Alvor: Medium; High fra 15 ms i gennemsnit.
|
||||
-- Versioner: Alle.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om commits venter på langsom skrivning til transaktionsloggen (WRITELOG).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Forskellen mellem to målinger. Fund hvis WRITELOG har mindst 1.000 waits i intervallet og gennemsnittet
|
||||
-- (wait_time_ms / waiting_tasks_count) er mindst 5 ms.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- >= 1.000 waits; gns. >= 5 ms; High fra 15 ms (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- WaitStatsCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), WaitStatsCollector.Sql2005, WaitStatsCollector.Sql2000
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:wait-stats)
|
||||
-- Delt script: SQL Scripts/_collectors/WaitStatsCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/WaitRules.cs : WriteLogLatencyRule.Evaluate
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt DBCC SQLPERF(WAITSTATS) (læser ventetider, SQL Server 2000),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- WaitStatsCollector: Kumulative ventetider. Reglerne bruger forskellen mellem to målinger; en genstart (nyt
|
||||
-- starttidspunkt) nulstiller.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt (nulstilling af kumulative tal)
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: WaitStatsCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2005
|
||||
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
|
||||
FROM sys.dm_os_wait_stats
|
||||
WHERE wait_time_ms > 0
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: WaitStatsCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2000
|
||||
DBCC SQLPERF(WAITSTATS) WITH NO_INFOMSGS
|
||||
GO
|
||||
88
SQL Scripts/SQLI-WAIT-006.sql
Normal file
88
SQL Scripts/SQLI-WAIT-006.sql
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-WAIT-006: Parallelle forespørgsler venter meget på hinanden
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WAIT-006
|
||||
-- Titel: Parallelle forespørgsler venter meget på hinanden
|
||||
-- Alvor: Medium; High fra 16 ventende tasks i gennemsnit.
|
||||
-- Versioner: Alle.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om parallelle forespørgsler venter meget på hinanden (CXPACKET, CXSYNC_PORT, CXSYNC_CONSUMER, EXCHANGE;
|
||||
-- CXCONSUMER regnes som godartet).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Forskellen mellem to målinger, uden godartede ventetyper. Fund hvis parallelisme-ventetyperne udgør mindst 30 %
|
||||
-- af al ventetid og i gennemsnit mindst 2 tasks venter.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Andel >= 30 %, gns. ventende >= 2; High fra 16 (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- WaitStatsCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), WaitStatsCollector.Sql2005, WaitStatsCollector.Sql2000
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:wait-stats)
|
||||
-- Delt script: SQL Scripts/_collectors/WaitStatsCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/WaitRules.cs : WaitRules.Create (DominantWaitRule "SQLI-WAIT-006",
|
||||
-- kategori Parallelism)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt DBCC SQLPERF(WAITSTATS) (læser ventetider, SQL Server 2000),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- WaitStatsCollector: Kumulative ventetider. Reglerne bruger forskellen mellem to målinger; en genstart (nyt
|
||||
-- starttidspunkt) nulstiller.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt (nulstilling af kumulative tal)
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: WaitStatsCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2005
|
||||
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
|
||||
FROM sys.dm_os_wait_stats
|
||||
WHERE wait_time_ms > 0
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: WaitStatsCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2000
|
||||
DBCC SQLPERF(WAITSTATS) WITH NO_INFOMSGS
|
||||
GO
|
||||
88
SQL Scripts/SQLI-WAIT-007.sql
Normal file
88
SQL Scripts/SQLI-WAIT-007.sql
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-WAIT-007: Contention på sider i hukommelsen (PAGELATCH)
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WAIT-007
|
||||
-- Titel: Contention på sider i hukommelsen (PAGELATCH)
|
||||
-- Alvor: Medium; High fra 4 ventende tasks i gennemsnit.
|
||||
-- Versioner: Alle.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Om der er contention på sider i hukommelsen (PAGELATCH_*), typisk tempdb-allokeringssider eller "last page
|
||||
-- insert".
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Forskellen mellem to målinger, uden godartede ventetyper. Fund hvis PAGELATCH_* udgør mindst 20 % af al ventetid
|
||||
-- og i gennemsnit mindst 0,5 task venter.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Andel >= 20 %, gns. ventende >= 0,5; High fra 4 (fast i koden).
|
||||
--
|
||||
-- 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+
|
||||
-- SQL Server 2000 har ikke VIEW SERVER STATE; se docs/legacy-versions.md (fx kræver DBCC SQLPERF(WAITSTATS) forhøjede rettigheder).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- WaitStatsCollector
|
||||
-- Fil: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs
|
||||
-- Medlemmer: Db.StartTimeSql(version), WaitStatsCollector.Sql2005, WaitStatsCollector.Sql2000
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:wait-stats)
|
||||
-- Delt script: SQL Scripts/_collectors/WaitStatsCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/Performance/WaitRules.cs : WaitRules.Create (DominantWaitRule "SQLI-WAIT-007",
|
||||
-- kategori PageLatch)
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT samt DBCC SQLPERF(WAITSTATS) (læser ventetider, SQL Server 2000),
|
||||
-- SET-sessionsindstillinger. Intet ændrer data, indstillinger eller objekter.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); en variant for en anden SQL Server-version end din kan fejle - det er forventet.
|
||||
-- Per-database-forespørgsler er vist for databasen msdb, som findes overalt: ret navnet til den
|
||||
-- database, du vil se.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- Forbindelsen: Sessionsindstillinger, agenten sætter på hver forbindelse
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- WaitStatsCollector: Kumulative ventetider. Reglerne bruger forskellen mellem to målinger; en genstart (nyt
|
||||
-- starttidspunkt) nulstiller.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: SQL Server 2008 og nyere: starttidspunkt (nulstilling af kumulative tal)
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2008+)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT sqlserver_start_time FROM sys.dm_os_sys_info)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005: starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2005)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT create_date FROM sys.databases WHERE database_id = 2)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti): starttidspunkt
|
||||
-- Kilde: WaitStatsCollector.StartTimeSql(2000)
|
||||
-- Kode: src/SQLInsight.Collectors/Db.cs : Db.StartTimeSql(version)
|
||||
SELECT (SELECT login_time FROM master.dbo.sysprocesses WHERE spid = 1)
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2005 og nyere
|
||||
-- Kilde: WaitStatsCollector.Sql2005
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2005
|
||||
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
|
||||
FROM sys.dm_os_wait_stats
|
||||
WHERE wait_time_ms > 0
|
||||
GO
|
||||
|
||||
-- Variant: SQL Server 2000 (legacy ODBC-sti)
|
||||
-- Kilde: WaitStatsCollector.Sql2000
|
||||
-- Kode: src/SQLInsight.Collectors/Performance/WaitStatsCollector.cs : WaitStatsCollector.Sql2000
|
||||
DBCC SQLPERF(WAITSTATS) WITH NO_INFOMSGS
|
||||
GO
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue