Compare commits
No commits in common. "main" and "v1.0.3" have entirely different histories.
523 changed files with 438 additions and 56346 deletions
|
|
@ -28,7 +28,6 @@ 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
|
||||
|
|
@ -38,20 +37,16 @@ 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.
|
||||
|
||||
En regel om en Windows-server eller et syntetisk tjek (fra 1.5, `SQLI-WIN-…`/`SQLI-SYN-…`) implementerer `IScopedRule<TContext>` i `src/SQLInsight.Rules/Servers/` og registreres i `WindowsServerRules.Create()` eller `SyntheticCheckRules.Create()` (dermed i `ServerRuleCatalog`). Dens `SQL Scripts/<id>.sql` har samme header; forespørgslerne mod Windows står ordret i kommentarer og skal stå i `src/SQLInsight.Servers/CimQueries.cs` (`ServerScriptTests` tjekker det). Agenten må kun læse: CIM-`SELECT`, hændelsesloggen og skrivebeskyttede metoder som Task Schedulers `GetInfoByName`, aldrig start/stop eller ændringer.
|
||||
|
||||
### 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). Også en community-regel skal have sin `SQL Scripts/<id>.sql` med forespørgslen ordret (se fx `SQL Scripts/COM-SEC-001.sql`).
|
||||
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).
|
||||
|
||||
## 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
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
<Product>SQLInsight Pro</Product>
|
||||
<Copyright>Copyright (c) SEOSoft</Copyright>
|
||||
<!-- Release version; set with -p:Version=… when publishing. Update checks compare against it. -->
|
||||
<Version>1.5.2</Version>
|
||||
<Version>1.0.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="$(MSBuildProjectName.EndsWith('Tests'))">
|
||||
|
|
|
|||
|
|
@ -22,15 +22,11 @@
|
|||
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.12" />
|
||||
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="10.0.12" />
|
||||
<PackageVersion Include="System.Diagnostics.EventLog" Version="10.0.12" />
|
||||
<PackageVersion Include="Microsoft.Management.Infrastructure" Version="3.0.0" />
|
||||
<PackageVersion Include="System.DirectoryServices.AccountManagement" Version="10.0.12" />
|
||||
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="10.0.12" />
|
||||
<PackageVersion Include="PDFsharp-MigraDoc" Version="6.2.4" />
|
||||
<PackageVersion Include="Markdig" Version="1.4.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.Systemd" Version="10.0.12" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="10.0.12" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.12" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.12" />
|
||||
<!-- Test -->
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageVersion Include="xunit" Version="2.9.3" />
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
SQLInsight Pro er et overvågningsværktøj til Microsoft SQL Server, skrevet i C# på .NET. Det kører hos kunden og forlader ikke netværket, medmindre kunden selv vælger det. Værktøjet nøjes ikke med at vise tal. Det forklarer, hvad der er galt, hvorfor det er et problem, og hvordan det løses. Rådene har samme niveau som dem, man får fra en erfaren DBA.
|
||||
|
||||
> **Status:** Fase 1–4 er implementeret: agent, 108 indbyggede regler (92 for SQL Server; fra 1.5 også 13 for Windows-servere og 3 for syntetiske tjek) plus community-regler, notifikationer, lokalt repository og web-UI, licenser, signerede opdateringer, SQLInsight Hub med portal, erfaring på tværs af kunder, PDF-rapporter og integration med Prometheus, Grafana og SCOM, plus MSI-installer, community-websted og Discourse-forum. Se [installation](docs/installation.md), [opdateringer](docs/opdatering.md), [integration](docs/integration.md), [rapporter](docs/rapporter.md), [egne regler](docs/regler.md), [Dynamics AX](docs/dynamics-ax.md), [Windows-servere](docs/windows-servere.md), [syntetiske tjek](docs/syntetiske-tjek.md), [databehandling](docs/databehandling.md), [community](docs/community.md), [Roadmap](#roadmap) og [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
> **Status:** Fase 1–4 er implementeret: agent, 61 indbyggede regler plus community-regler, notifikationer, lokalt repository og web-UI, licenser, signerede opdateringer, SQLInsight Hub med portal, erfaring på tværs af kunder, PDF-rapporter og integration med Prometheus, Grafana og SCOM, plus MSI-installer, community-websted og Discourse-forum. Se [installation](docs/installation.md), [opdateringer](docs/opdatering.md), [integration](docs/integration.md), [rapporter](docs/rapporter.md), [egne regler](docs/regler.md), [databehandling](docs/databehandling.md), [community](docs/community.md), [Roadmap](#roadmap) og [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -205,7 +205,6 @@ Hvert **finding** indeholder:
|
|||
### Fase 4: Videre
|
||||
- [x] Anbefalinger på tværs af kunder: Hubben ser, hvilke fund der forsvinder efter en opdatering, og agenterne viser "hos 4 kunder forsvandt dette efter CU21" på fundet. Deles kun samlet og anonymt fra mindst 3 kunder. Se [docs/hub.md](docs/hub.md#erfaring-på-tværs-af-kunder)
|
||||
- [x] Rapporter (PDF) til ledelse og compliance: nøgletal, sammenfatning i almindeligt sprog, kontroller, instanser og alvorlige fund. Kan hentes i webbrugerfladen og sendes månedligt på mail. Se [docs/rapporter.md](docs/rapporter.md)
|
||||
- [x] Rettighedsrevision: sysadmin og øvrige serverroller med Windows-grupper foldet ud via AD, ændringer med hvem/hvornår fra default trace, fund ved nye medlemmer og revisionsrapport (PDF). Se [docs/rettigheder.md](docs/rettigheder.md)
|
||||
- [x] Mulighed for, at community selv bidrager med regler: regler som SQL i JSON (community via pull request og signeret regelpakke, lokale regler hos kunden), med validering og `rules test` mod en instans. Se [docs/regler.md](docs/regler.md)
|
||||
- [x] API til integration med eksisterende monitorering: JSON-API og Prometheus-endpoint med API-tokens, Grafana-dashboard, og Windows' hændelseslog med faste event-id'er til SCOM. Se [docs/integration.md](docs/integration.md)
|
||||
- [x] Community-websted (download af signerede udgivelser, dokumentation, SQL Server-versioner, regler, support) og Discourse-forum på dansk med kategorier, løste svar og opsætning som kode. Se [docs/community.md](docs/community.md)
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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).
|
||||
-- Kører kun i Dynamics AX-databaser (den fælles AX-genkendelse). Axapta 3.0: verificeret mod en kundes
|
||||
-- skema; AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- 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). Reglen er markeret "dynamicsAx" (fra 1.4): forespørgslen køres kun i de overvågede
|
||||
-- databaser (CustomQueryCollector.DatabasesSql), som AX-genkendelsen (AxDatabaseDetector) genkender som Dynamics AX;
|
||||
-- er der ingen, er reglen "ikke relevant". Fund går kun til SQLInsight Hub for databaser med AX-tilvalget.
|
||||
-- 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
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.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 og AX-genkendelsen
|
||||
-- via [db].sys.sp_executesql (kun metadata, ingen AX-tabeldata). 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.
|
||||
-- Forespørgslerne i databasen er vist for AXDB: ret [AXDB] til din Dynamics AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke af databaserne er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: reglens forespørgsel i hver genkendt Dynamics AX-database
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- 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 overvåget database, som AX-genkendelsen herover har genkendt. Ret [AXDB] til din AX-database.
|
||||
USE [AXDB];
|
||||
SELECT CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)) AS [sql_version] WHERE COLUMNPROPERTY((SELECT TOP 1 object_id FROM sys.tables WHERE name = N'SQLDICTIONARY'), N'RECID', 'Precision') = 10
|
||||
GO
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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).
|
||||
-- Kører kun i Dynamics AX-databaser (den fælles AX-genkendelse). Axapta 3.0: verificeret mod en kundes
|
||||
-- skema; AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- 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). Reglen er markeret "dynamicsAx" (fra 1.4): forespørgslen køres kun i de overvågede
|
||||
-- databaser (CustomQueryCollector.DatabasesSql), som AX-genkendelsen (AxDatabaseDetector) genkender som Dynamics AX;
|
||||
-- er der ingen, er reglen "ikke relevant". Fund går kun til SQLInsight Hub for databaser med AX-tilvalget.
|
||||
-- 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
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.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 og AX-genkendelsen
|
||||
-- via [db].sys.sp_executesql (kun metadata, ingen AX-tabeldata). 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.
|
||||
-- Forespørgslerne i databasen er vist for AXDB: ret [AXDB] til din Dynamics AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke af databaserne er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: reglens forespørgsel i hver genkendt Dynamics AX-database
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- 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 overvåget database, som AX-genkendelsen herover har genkendt. Ret [AXDB] til din AX-database.
|
||||
USE [AXDB];
|
||||
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 COLUMNPROPERTY((SELECT TOP 1 object_id FROM sys.tables WHERE name = N'SQLDICTIONARY'), N'RECID', 'Precision') = 10
|
||||
GO
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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).
|
||||
-- Kører kun i Dynamics AX-databaser (den fælles AX-genkendelse). Axapta 3.0: verificeret mod en kundes
|
||||
-- skema; AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- 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). Reglen er markeret "dynamicsAx" (fra 1.4): forespørgslen køres kun i de overvågede
|
||||
-- databaser (CustomQueryCollector.DatabasesSql), som AX-genkendelsen (AxDatabaseDetector) genkender som Dynamics AX;
|
||||
-- er der ingen, er reglen "ikke relevant". Fund går kun til SQLInsight Hub for databaser med AX-tilvalget.
|
||||
-- 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
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.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 og AX-genkendelsen
|
||||
-- via [db].sys.sp_executesql (kun metadata, ingen AX-tabeldata). 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.
|
||||
-- Forespørgslerne i databasen er vist for AXDB: ret [AXDB] til din Dynamics AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke af databaserne er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: reglens forespørgsel i hver genkendt Dynamics AX-database
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- 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 overvåget database, som AX-genkendelsen herover har genkendt. Ret [AXDB] til din AX-database.
|
||||
USE [AXDB];
|
||||
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
|
||||
GO
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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).
|
||||
-- Kører kun i Dynamics AX-databaser (den fælles AX-genkendelse). Axapta 3.0: verificeret mod en kundes
|
||||
-- skema; AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- 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). Reglen er markeret "dynamicsAx" (fra 1.4): forespørgslen køres kun i de overvågede
|
||||
-- databaser (CustomQueryCollector.DatabasesSql), som AX-genkendelsen (AxDatabaseDetector) genkender som Dynamics AX;
|
||||
-- er der ingen, er reglen "ikke relevant". Fund går kun til SQLInsight Hub for databaser med AX-tilvalget.
|
||||
-- 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
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.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 og AX-genkendelsen
|
||||
-- via [db].sys.sp_executesql (kun metadata, ingen AX-tabeldata). 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.
|
||||
-- Forespørgslerne i databasen er vist for AXDB: ret [AXDB] til din Dynamics AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke af databaserne er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: reglens forespørgsel i hver genkendt Dynamics AX-database
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- 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 overvåget database, som AX-genkendelsen herover har genkendt. Ret [AXDB] til din AX-database.
|
||||
USE [AXDB];
|
||||
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
|
||||
GO
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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).
|
||||
-- Kører kun i Dynamics AX-databaser (den fælles AX-genkendelse). Axapta 3.0: verificeret mod en kundes
|
||||
-- skema; AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- 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). Reglen er markeret "dynamicsAx" (fra 1.4): forespørgslen køres kun i de overvågede
|
||||
-- databaser (CustomQueryCollector.DatabasesSql), som AX-genkendelsen (AxDatabaseDetector) genkender som Dynamics AX;
|
||||
-- er der ingen, er reglen "ikke relevant". Fund går kun til SQLInsight Hub for databaser med AX-tilvalget.
|
||||
-- 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
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.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 og AX-genkendelsen
|
||||
-- via [db].sys.sp_executesql (kun metadata, ingen AX-tabeldata). 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.
|
||||
-- Forespørgslerne i databasen er vist for AXDB: ret [AXDB] til din Dynamics AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke af databaserne er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: reglens forespørgsel i hver genkendt Dynamics AX-database
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- 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 overvåget database, som AX-genkendelsen herover har genkendt. Ret [AXDB] til din AX-database.
|
||||
USE [AXDB];
|
||||
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') HAVING COUNT(*) > 0
|
||||
GO
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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).
|
||||
-- Kører kun i Dynamics AX-databaser (den fælles AX-genkendelse). Axapta 3.0: verificeret mod en kundes
|
||||
-- skema; AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- 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). Reglen er markeret "dynamicsAx" (fra 1.4): forespørgslen køres kun i de overvågede
|
||||
-- databaser (CustomQueryCollector.DatabasesSql), som AX-genkendelsen (AxDatabaseDetector) genkender som Dynamics AX;
|
||||
-- er der ingen, er reglen "ikke relevant". Fund går kun til SQLInsight Hub for databaser med AX-tilvalget.
|
||||
-- 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
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.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 og AX-genkendelsen
|
||||
-- via [db].sys.sp_executesql (kun metadata, ingen AX-tabeldata). 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.
|
||||
-- Forespørgslerne i databasen er vist for AXDB: ret [AXDB] til din Dynamics AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke af databaserne er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: reglens forespørgsel i hver genkendt Dynamics AX-database
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- 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 overvåget database, som AX-genkendelsen herover har genkendt. Ret [AXDB] til din AX-database.
|
||||
USE [AXDB];
|
||||
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 HAVING COUNT(*) > 0
|
||||
GO
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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).
|
||||
-- Kører kun i Dynamics AX-databaser (den fælles AX-genkendelse). Axapta 3.0: verificeret mod en kundes
|
||||
-- skema; AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- 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). Reglen er markeret "dynamicsAx" (fra 1.4): forespørgslen køres kun i de overvågede
|
||||
-- databaser (CustomQueryCollector.DatabasesSql), som AX-genkendelsen (AxDatabaseDetector) genkender som Dynamics AX;
|
||||
-- er der ingen, er reglen "ikke relevant". Fund går kun til SQLInsight Hub for databaser med AX-tilvalget.
|
||||
-- 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
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.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 og AX-genkendelsen
|
||||
-- via [db].sys.sp_executesql (kun metadata, ingen AX-tabeldata). 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.
|
||||
-- Forespørgslerne i databasen er vist for AXDB: ret [AXDB] til din Dynamics AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke af databaserne er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- CustomQueryCollector: reglens forespørgsel i hver genkendt Dynamics AX-database
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- 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 overvåget database, som AX-genkendelsen herover har genkendt. Ret [AXDB] til din AX-database.
|
||||
USE [AXDB];
|
||||
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)
|
||||
GO
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,288 +0,0 @@
|
|||
# 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)).
|
||||
|
||||
Fra 1.5 har også reglerne for Windows-servere (`SQLI-WIN-…`) og syntetiske tjek (`SQLI-SYN-…`) en fil her, med samme
|
||||
header. De fleste af dem sender ingen SQL: forespørgslerne mod Windows (CIM/WQL og hændelseslogsfilteret) står ordret i
|
||||
kommentarer, så de kan gennemgås på samme måde (se [Windows-servere og syntetiske tjek](#windows-servere-og-syntetiske-tjek-fra-15)).
|
||||
|
||||
## 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. |
|
||||
| `_collectors/AxDatabaseDetector.sql`, `_collectors/AxBatchCollector.sql`, `_collectors/AxSequenceCollector.sql` | Dynamics AX (fra 1.4): den fælles AX-genkendelse og læsningen af batchjob, nummerserier og RecId i AX-databasen. AX-forespørgslerne er vist for hver AX-version, SQLInsight har et skema for (Axapta 3.0, AX 4.0, AX 2009 og AX 2012), og for databasen `AXDB`. |
|
||||
| `_collectors/DatabaseDiscovery.sql`, `_collectors/PermissionCheck.sql` | Søgningen efter databaser (med Dynamics AX-genkendelse) og forbindelsestesten med rettighedstjek under *Servere og databaser* (fra 1.3). De køres kun, når der bedes om dem i webbrugerfladen, og søgningen desuden hver time. |
|
||||
| `_collectors/SyntheticCheckRunner.sql` | Det syntetiske SQL-tjek (fra 1.5): sessionsindstillingerne, `USE`, transaktionen og standardforespørgslen. Tjekkets egen forespørgsel køres i stedet for `SELECT 1`, og transaktionen rulles altid tilbage. |
|
||||
|
||||
## 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`.
|
||||
Ingen undtagelser: heller ikke midlertidige tabeller i tempdb. Dynamics AX-læsningerne (fra 1.4) kører som
|
||||
`EXEC [AXDB].sys.sp_executesql N'…'`, så sessionen aldrig skifter database; batchen i strengen er selv kun SELECT med
|
||||
`TOP` (READ COMMITTED med `SET LOCK_TIMEOUT 2000`, eller SNAPSHOT, aldrig NOLOCK), og testen tjekker den på samme måde.
|
||||
- **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-…`).
|
||||
|
||||
## Windows-servere og syntetiske tjek (fra 1.5)
|
||||
|
||||
- **`SQLI-WIN-…`** sender ingen SQL. Filen har samme header som de andre regler (rettighederne er dem, som
|
||||
`db/permissions/grant-windows-server.ps1` giver agentens konto, aldrig lokal administrator) og viser derefter, i
|
||||
kommentarer, de præcise CIM/WQL-forespørgsler (kun `SELECT`), XPath-filteret til hændelsesloggen og det eneste
|
||||
metodekald, Task Schedulers skrivebeskyttede `GetInfoByName`, samt PowerShell til at efterprøve dem. Agenten starter,
|
||||
stopper eller ændrer intet på serveren. Filerne kan åbnes i SSMS, men gør intet.
|
||||
- **`SQLI-SYN-001` og `SQLI-SYN-002`** viser præcis det, et syntetisk SQL-tjek sender: sessionsindstillingerne, `USE`
|
||||
(kun med en database), `BEGIN TRANSACTION`, forespørgslen (standard `SELECT 1`) og `IF @@TRANCOUNT > 0 ROLLBACK
|
||||
TRANSACTION`, der altid køres bagefter. En egen forespørgsel skal være én skrivebeskyttet SELECT
|
||||
(`src/SQLInsight.Core/CustomRules/ReadOnlyQuery.cs`). TCP-, HTTP-, DNS- og AX-tjek sender ingen SQL.
|
||||
- **`SQLI-SYN-003`** (TLS-certifikatet) sender ingen SQL.
|
||||
|
||||
## 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, fra 1.5,
|
||||
`ServerRuleCatalog`) 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. Kun Windows-server- og syntetiske-tjek-reglerne må være uden SQL-blokke.
|
||||
- `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`: ingen skrivende sætninger, heller ikke `SELECT … INTO #temp` - heller ikke i batchen i en
|
||||
`EXEC [db].sys.sp_executesql N'…'`.
|
||||
- `tests/SQLInsight.Collectors.Tests/SqlScriptTests.cs` (Dynamics AX): hver AX-regel og AX-collector viser SQL'en for alle
|
||||
AX-versioner, og headeren siger, hvad der ikke er verificeret mod kundedata.
|
||||
- `tests/SQLInsight.Servers.Tests/ServerScriptTests.cs` (fra 1.5): hver CIM/WQL-forespørgsel og hvert
|
||||
hændelseslogsfilter i `src/SQLInsight.Servers/CimQueries.cs` står ordret i en `SQLI-WIN-…`-fil, og hver af filerne viser
|
||||
mindst én af dem. `tests/SQLInsight.Rules.Tests/ServerRuleScriptTests.cs`: regel-id og titel i headeren er reglens.
|
||||
|
||||
Er en collectors SQL ændret, kan blokkene skrives om fra koden: kør testene med `SQLINSIGHT_UPDATE_SQL_SCRIPTS=1`
|
||||
(kommentarlinjerne bevares). Blokke med værdier, agenten beregner ved kørsel (⟪…⟫), udfyldes kun, når de er nye; værdien så sættes ind i hånden.
|
||||
|
||||
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
|
||||
|
||||
124 regler: 108 indbyggede (C#: 92 for SQL Server, 13 for Windows-servere og 3 for syntetiske tjek, fra 1.5) 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-AX-001 | [SQLI-AX-001.sql](SQLI-AX-001.sql) | Dynamics AX-batchjob er endt med fejl | AxDatabaseDetector, AxBatchCollector | High |
|
||||
| SQLI-AX-002 | [SQLI-AX-002.sql](SQLI-AX-002.sql) | Dynamics AX-batchjob kører længere end normalt | AxDatabaseDetector, AxBatchCollector | Medium; High, når kørslen er dobbelt så lang som grænsen. |
|
||||
| SQLI-AX-003 | [SQLI-AX-003.sql](SQLI-AX-003.sql) | Dynamics AX-batchjob er ikke startet til tiden | AxDatabaseDetector, AxBatchCollector | Medium; High, når jobbet i praksis aldrig er startet. |
|
||||
| SQLI-AX-004 | [SQLI-AX-004.sql](SQLI-AX-004.sql) | Dynamics AX-batchjob hænger i Udfører | AxDatabaseDetector, AxBatchCollector | High |
|
||||
| SQLI-AX-005 | [SQLI-AX-005.sql](SQLI-AX-005.sql) | Dynamics AX-nummerserie er ved at løbe tør | AxDatabaseDetector, AxSequenceCollector | Medium; High over den kritiske procent eller inden for de kritiske dage; Critical, når serien er opbrugt. |
|
||||
| SQLI-AX-006 | [SQLI-AX-006.sql](SQLI-AX-006.sql) | Dynamics AX-nummerseriens format er for kort til Højeste | AxDatabaseDetector, AxSequenceCollector | Medium; High, når NEXTREC allerede er større end formatets kapacitet. |
|
||||
| SQLI-AX-007 | [SQLI-AX-007.sql](SQLI-AX-007.sql) | Spærret Dynamics AX-nummerserie bruges stadig | AxDatabaseDetector, AxSequenceCollector | Medium |
|
||||
| SQLI-AX-008 | [SQLI-AX-008.sql](SQLI-AX-008.sql) | Kontinuerlig Dynamics AX-nummerserie er ikke ryddet op | AxDatabaseDetector, AxSequenceCollector | Low |
|
||||
| SQLI-AX-009 | [SQLI-AX-009.sql](SQLI-AX-009.sql) | Dynamics AX RecId er ved at løbe tør | AxDatabaseDetector, AxSequenceCollector | Axapta 3.0: High/Critical efter grænserne; 64-bit: High; Critical, når RecId er opbrugt. |
|
||||
| SQLI-AX-010 | [SQLI-AX-010.sql](SQLI-AX-010.sql) | AX-bruger blokerer andre | AxDatabaseDetector, BlockingCollector | Medium; High ved ventetid over 5 minutter eller mindst 10 blokerede sessioner. |
|
||||
| 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-SYN-001 | [SQLI-SYN-001.sql](SQLI-SYN-001.sql) | Et syntetisk tjek fejler | SyntheticCheckRunner | High. |
|
||||
| SQLI-SYN-002 | [SQLI-SYN-002.sql](SQLI-SYN-002.sql) | Et syntetisk tjek svarer langsomt | SyntheticCheckRunner | Medium. |
|
||||
| SQLI-SYN-003 | [SQLI-SYN-003.sql](SQLI-SYN-003.sql) | TLS-certifikatet udløber snart | SyntheticCheckRunner (HTTPS, ingen SQL) | Medium; High inden for CertificateCriticalDays; Critical når det er udløbet. |
|
||||
| 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. |
|
||||
| SQLI-WIN-001 | [SQLI-WIN-001.sql](SQLI-WIN-001.sql) | CPU-forbruget er højt i længere tid | CimWindowsServerSource (Windows, ingen SQL) | High; Critical når gennemsnittet er 98 % eller derover. |
|
||||
| SQLI-WIN-002 | [SQLI-WIN-002.sql](SQLI-WIN-002.sql) | Serveren har næsten ingen ledig hukommelse | CimWindowsServerSource (Windows, ingen SQL) | Medium; High under 2 % og under 256 MB. |
|
||||
| SQLI-WIN-003 | [SQLI-WIN-003.sql](SQLI-WIN-003.sql) | Serveren pager hukommelse til disk | CimWindowsServerSource (Windows, ingen SQL) | Medium. |
|
||||
| SQLI-WIN-004 | [SQLI-WIN-004.sql](SQLI-WIN-004.sql) | Den reserverede hukommelse (commit) er tæt på grænsen | CimWindowsServerSource (Windows, ingen SQL) | Medium; High ved 97 % eller derover. |
|
||||
| SQLI-WIN-005 | [SQLI-WIN-005.sql](SQLI-WIN-005.sql) | Lidt ledig plads på et drev | CimWindowsServerSource (Windows, ingen SQL) | Medium under FreePercent, High under CriticalFreePercent, Critical under 1 GB eller 1 %. |
|
||||
| SQLI-WIN-006 | [SQLI-WIN-006.sql](SQLI-WIN-006.sql) | Et drev bliver fuldt om få dage | CimWindowsServerSource (Windows, ingen SQL) | Medium; High inden for 7 dage; Critical inden for 2 dage. |
|
||||
| SQLI-WIN-007 | [SQLI-WIN-007.sql](SQLI-WIN-007.sql) | En tjeneste, der skal starte automatisk, kører ikke | CimWindowsServerSource (Windows, ingen SQL) | Medium. |
|
||||
| SQLI-WIN-008 | [SQLI-WIN-008.sql](SQLI-WIN-008.sql) | En overvåget tjeneste kører ikke | CimWindowsServerSource (Windows, ingen SQL) | High når tjenesten ikke kører; Medium når den ikke findes (eller ikke kan ses). |
|
||||
| SQLI-WIN-009 | [SQLI-WIN-009.sql](SQLI-WIN-009.sql) | Fejl i Windows' hændelseslog | CimWindowsServerSource (Windows, ingen SQL) | High: disk/filsystem, ressourcer, niveau Critical, tjeneste stoppet 3+ gange. Medium: tjeneste stoppet, program gik ned, Dynamics AX. Low: almindelige fejl der gentager sig. (Uventet nedlukning: se SQLI-WIN-010.) |
|
||||
| SQLI-WIN-010 | [SQLI-WIN-010.sql](SQLI-WIN-010.sql) | Serveren er genstartet | CimWindowsServerSource (Windows, ingen SQL) | High ved uventet genstart; Info ved genstart uden tegn på at den var uventet; Low når hændelsesloggen ikke kan læses. |
|
||||
| SQLI-WIN-011 | [SQLI-WIN-011.sql](SQLI-WIN-011.sql) | Serveren er ikke genstartet i lang tid | CimWindowsServerSource (Windows, ingen SQL) | Low. |
|
||||
| SQLI-WIN-012 | [SQLI-WIN-012.sql](SQLI-WIN-012.sql) | En planlagt opgave fejlede sidste gang, den kørte | CimWindowsServerSource (Windows, ingen SQL) | Medium. |
|
||||
| SQLI-WIN-013 | [SQLI-WIN-013.sql](SQLI-WIN-013.sql) | En planlagt opgave kørte ikke, da den skulle | CimWindowsServerSource (Windows, ingen SQL) | Medium. |
|
||||
| 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) | 2 regler |
|
||||
| [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 |
|
||||
| [AxDatabaseDetector](_collectors/AxDatabaseDetector.sql) | `src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs` | 1 time som standard (SQLInsight:CollectorIntervals:dynamics-ax); uden AX-læseadgang hvert 5. minut | SQL Server 2005 og nyere | 17 regler (alle AX-regler) |
|
||||
| [AxBatchCollector](_collectors/AxBatchCollector.sql) | `src/SQLInsight.Collectors/DynamicsAx/AxBatchCollector.cs` | 5 min som standard (SQLInsight:CollectorIntervals:dynamics-ax-batch) | SQL Server 2005 og nyere; kræver valgfri AX-læseadgang | 4 regler |
|
||||
| [AxSequenceCollector](_collectors/AxSequenceCollector.sql) | `src/SQLInsight.Collectors/DynamicsAx/AxSequenceCollector.cs` | 1 time som standard (SQLInsight:CollectorIntervals:dynamics-ax-sequences) | SQL Server 2005 og nyere; kræver valgfri AX-læseadgang | 5 regler |
|
||||
| [SyntheticCheckRunner](_collectors/SyntheticCheckRunner.sql) | `src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs` | tjekkets eget interval (standard 300 sek, mindst 60) og "Kør nu" | SQL Server 2005 og nyere | 2 regler (SQLI-SYN-001, SQLI-SYN-002) |
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AX-001: Dynamics AX-batchjob er endt med fejl
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AX-001
|
||||
-- Titel: Dynamics AX-batchjob er endt med fejl
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2005 og nyere (ikke 2000). Axapta 3.0: verificeret mod en kundes skema (docs/dynamics-ax/
|
||||
-- schema-ax30.tsv). AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Et batchjob i Dynamics AX er stoppet med fejl. Det, jobbet skulle gøre (bogføring, lagerafslutning, integration
|
||||
-- ...), er ikke gjort eller kun delvist, og gentagne job fortsætter ikke nødvendigvis af sig selv.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Et fund pr. job, når jobbet nu har status Fejl og sluttede (eller var planlagt) inden for grænsen, eller når jobbet
|
||||
-- venter på næste gentagelse, men dets seneste kørsel i SQLInsights egen historik (insight.AxBatchRuns) endte med
|
||||
-- fejl inden for grænsen.
|
||||
-- STATUS oversættes af versionens adapter: AX 2009+ 0 Tilbageholdt, 1 Venter, 2 Udfører, 3 Fejl, 4 Afsluttet,
|
||||
-- 5 Klar, 6 Ikke kørt, 7 Annullerer, 8 Annulleret; Axapta 3.0/4.0 samme rækkefølge (1 og 4 kontrolleret mod kundedata 2026-10-03):
|
||||
-- 0 Tilbageholdt, 1 Venter, 2 Udfører, 3 Fejl, 4 Afsluttet. Højst 25 fund pr. database.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:DynamicsAx:BatchFailedLookbackHours = 24: fejl inden for så mange timer rapporteres.
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql og grant-dynamics-ax-read.sql):
|
||||
-- Valgfri AX-læseadgang, kun SELECT (db/permissions/grant-dynamics-ax-read.sql; [bruger] = agentens databasebruger):
|
||||
-- Axapta 3.0: GRANT SELECT ON [bmssa].[BATCH] TO [bruger];
|
||||
-- AX 4.0: GRANT SELECT ON [dbo].[BATCH] TO [bruger];
|
||||
-- AX 2009/2012/F&O: GRANT SELECT ON [dbo].[BATCHJOB] TO [bruger];
|
||||
-- GRANT SELECT ON [dbo].[BATCHJOBHISTORY] TO [bruger];
|
||||
-- Mangler den, er reglen "ikke målbar" med den nøjagtige GRANT for databasen (også under Dynamics AX → AX-databaser
|
||||
-- og GET /api/v1/dynamics-ax/grant-script). Uden GRANT ændres intet.
|
||||
-- Genkendelsen: kun grant-least-privilege.sql (VIEW ANY DEFINITION; CONNECT ANY DATABASE fra 2014, ellers en
|
||||
-- databasebruger: CREATE USER [agent] FOR LOGIN [agent];).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.sql
|
||||
-- AxBatchCollector
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxBatchCollector.cs; SQL: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs
|
||||
-- Medlemmer: AxSchemaAdapter.BatchJobs(database), AxSchemaAdapter.BatchHistory(database, afterRecId), AxSql.InDatabase
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:dynamics-ax-batch)
|
||||
-- Delt script: SQL Scripts/_collectors/AxBatchCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/DynamicsAx/DynamicsAxRules.cs : AxBatchFailedRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT med TOP og SET-sessionsindstillinger. AX-tabellerne læses i AX-databasen via
|
||||
-- [db].sys.sp_executesql (sessionen skifter aldrig database) under READ COMMITTED med SET LOCK_TIMEOUT 2000
|
||||
-- (SNAPSHOT, når databasen tillader det), aldrig NOLOCK; bagefter sættes agentens sessionsindstillinger
|
||||
-- igen. Intet ændrer data, indstillinger eller objekter. Kun i databaser genkendt som AX og valgt til
|
||||
-- overvågning.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); varianter for andre AX-versioner end din fejler eller giver ingen rækker - det er forventet.
|
||||
-- AX-forespørgslerne er vist for databasen AXDB: ret [AXDB] til din AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke overvågede databaser er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxBatchCollector: Batchjob og kørselshistorik i AX-databasen (valgfri AX-læseadgang)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Axapta 3.0 (skema bmssa, verificeret mod kundedata): batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(3.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(b.[RECID] AS bigint), b.[CLASSNUM], CAST(NULL AS nvarchar(60)), b.[COMPANY], b.[GROUPID], b.[STATUS], b.[STARTDATE], b.[STARTTIME], CAST(NULL AS datetime), CAST(NULL AS int), b.[ENDDATE], b.[ENDTIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [bmssa].[BATCH] b ORDER BY b.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 4.0 (skema dbo) - ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(4.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(b.[RECID] AS bigint), b.[CLASSNUM], CAST(NULL AS nvarchar(60)), b.[COMPANY], b.[GROUPID], b.[STATUS], b.[STARTDATE], b.[STARTTIME], CAST(NULL AS datetime), CAST(NULL AS int), b.[ENDDATE], b.[ENDTIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCH] b ORDER BY b.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(2009)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(j.[RECID] AS bigint), CAST(NULL AS int), j.[CAPTION], j.[COMPANY], CAST(NULL AS nvarchar(20)), j.[STATUS], j.[ORIGSTARTDATETIME], CAST(NULL AS int), j.[STARTDATETIME], CAST(NULL AS int), j.[ENDDATETIME], CAST(NULL AS int), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOB] j ORDER BY j.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, første læsning (de nyeste)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2009, første)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId: null) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h ORDER BY h.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, de næste læsninger (fra den højeste RECID, SQLInsight har læst, minus overlappet)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2009, næste)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId) via AxSql.InDatabase
|
||||
-- Agenten indsætter den højeste RECID, den har læst, minus overlappet, hvor der her står 0.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (3000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h WHERE h.[RECID] > 0 ORDER BY h.[RECID]';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(2012)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(j.[RECID] AS bigint), CAST(NULL AS int), j.[CAPTION], j.[COMPANY], CAST(NULL AS nvarchar(20)), j.[STATUS], j.[ORIGSTARTDATETIME], CAST(NULL AS int), j.[STARTDATETIME], CAST(NULL AS int), j.[ENDDATETIME], CAST(NULL AS int), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOB] j ORDER BY j.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, første læsning (de nyeste)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2012, første)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId: null) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h ORDER BY h.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, de næste læsninger (fra den højeste RECID, SQLInsight har læst, minus overlappet)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2012, næste)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId) via AxSql.InDatabase
|
||||
-- Agenten indsætter den højeste RECID, den har læst, minus overlappet, hvor der her står 0.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (3000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h WHERE h.[RECID] > 0 ORDER BY h.[RECID]';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AX-002: Dynamics AX-batchjob kører længere end normalt
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AX-002
|
||||
-- Titel: Dynamics AX-batchjob kører længere end normalt
|
||||
-- Alvor: Medium; High, når kørslen er dobbelt så lang som grænsen.
|
||||
-- Versioner: SQL Server 2005 og nyere (ikke 2000). Axapta 3.0: verificeret mod en kundes skema (docs/dynamics-ax/
|
||||
-- schema-ax30.tsv). AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Et kørende batchjob har kørt meget længere end jobbets egne seneste kørsler. Det kan skyldes blokering, en ændret
|
||||
-- datamængde, en dårlig plan, eller at jobbet hænger - og imens kan det holde låse, som brugerne venter på.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For job med status Udfører: kørt = nu - faktisk start (AX 2009+: BATCHJOB.STARTDATETIME; Axapta 3.0/4.0 gemmer
|
||||
-- ikke den faktiske start, så det er første gang, SQLInsight så jobbet køre). Grænse = max(faktor x 90 %-fraktil af
|
||||
-- jobbets seneste op til 20 vellykkede kørsler, minimum). Historikken er SQLInsights egen (insight.AxBatchRuns): fra
|
||||
-- BATCHJOBHISTORY i AX 2009+, ellers de kørsler, SQLInsight selv ser blive afsluttet. Hænger jobbet (SQLI-AX-004),
|
||||
-- gives kun det fund.
|
||||
-- STATUS oversættes af versionens adapter: AX 2009+ 0 Tilbageholdt, 1 Venter, 2 Udfører, 3 Fejl, 4 Afsluttet,
|
||||
-- 5 Klar, 6 Ikke kørt, 7 Annullerer, 8 Annulleret; Axapta 3.0/4.0 samme rækkefølge (1 og 4 kontrolleret mod kundedata 2026-10-03):
|
||||
-- 0 Tilbageholdt, 1 Venter, 2 Udfører, 3 Fejl, 4 Afsluttet. Højst 25 fund pr. database.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:DynamicsAx:BatchLongRunningFactor = 2.0: kørt mere end så mange gange jobbets 90 %-fraktil
|
||||
-- SQLInsight:DynamicsAx:BatchLongRunningMinimumMinutes = 10: men aldrig under så mange minutter
|
||||
-- SQLInsight:DynamicsAx:BatchHistoryMinimumRuns = 5: så mange tidligere kørsler skal der være
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql og grant-dynamics-ax-read.sql):
|
||||
-- Valgfri AX-læseadgang, kun SELECT (db/permissions/grant-dynamics-ax-read.sql; [bruger] = agentens databasebruger):
|
||||
-- Axapta 3.0: GRANT SELECT ON [bmssa].[BATCH] TO [bruger];
|
||||
-- AX 4.0: GRANT SELECT ON [dbo].[BATCH] TO [bruger];
|
||||
-- AX 2009/2012/F&O: GRANT SELECT ON [dbo].[BATCHJOB] TO [bruger];
|
||||
-- GRANT SELECT ON [dbo].[BATCHJOBHISTORY] TO [bruger];
|
||||
-- Mangler den, er reglen "ikke målbar" med den nøjagtige GRANT for databasen (også under Dynamics AX → AX-databaser
|
||||
-- og GET /api/v1/dynamics-ax/grant-script). Uden GRANT ændres intet.
|
||||
-- Genkendelsen: kun grant-least-privilege.sql (VIEW ANY DEFINITION; CONNECT ANY DATABASE fra 2014, ellers en
|
||||
-- databasebruger: CREATE USER [agent] FOR LOGIN [agent];).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.sql
|
||||
-- AxBatchCollector
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxBatchCollector.cs; SQL: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs
|
||||
-- Medlemmer: AxSchemaAdapter.BatchJobs(database), AxSchemaAdapter.BatchHistory(database, afterRecId), AxSql.InDatabase
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:dynamics-ax-batch)
|
||||
-- Delt script: SQL Scripts/_collectors/AxBatchCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/DynamicsAx/DynamicsAxRules.cs : AxBatchLongRunningRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT med TOP og SET-sessionsindstillinger. AX-tabellerne læses i AX-databasen via
|
||||
-- [db].sys.sp_executesql (sessionen skifter aldrig database) under READ COMMITTED med SET LOCK_TIMEOUT 2000
|
||||
-- (SNAPSHOT, når databasen tillader det), aldrig NOLOCK; bagefter sættes agentens sessionsindstillinger
|
||||
-- igen. Intet ændrer data, indstillinger eller objekter. Kun i databaser genkendt som AX og valgt til
|
||||
-- overvågning.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); varianter for andre AX-versioner end din fejler eller giver ingen rækker - det er forventet.
|
||||
-- AX-forespørgslerne er vist for databasen AXDB: ret [AXDB] til din AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke overvågede databaser er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxBatchCollector: Batchjob og kørselshistorik i AX-databasen (valgfri AX-læseadgang)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Axapta 3.0 (skema bmssa, verificeret mod kundedata): batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(3.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(b.[RECID] AS bigint), b.[CLASSNUM], CAST(NULL AS nvarchar(60)), b.[COMPANY], b.[GROUPID], b.[STATUS], b.[STARTDATE], b.[STARTTIME], CAST(NULL AS datetime), CAST(NULL AS int), b.[ENDDATE], b.[ENDTIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [bmssa].[BATCH] b ORDER BY b.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 4.0 (skema dbo) - ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(4.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(b.[RECID] AS bigint), b.[CLASSNUM], CAST(NULL AS nvarchar(60)), b.[COMPANY], b.[GROUPID], b.[STATUS], b.[STARTDATE], b.[STARTTIME], CAST(NULL AS datetime), CAST(NULL AS int), b.[ENDDATE], b.[ENDTIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCH] b ORDER BY b.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(2009)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(j.[RECID] AS bigint), CAST(NULL AS int), j.[CAPTION], j.[COMPANY], CAST(NULL AS nvarchar(20)), j.[STATUS], j.[ORIGSTARTDATETIME], CAST(NULL AS int), j.[STARTDATETIME], CAST(NULL AS int), j.[ENDDATETIME], CAST(NULL AS int), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOB] j ORDER BY j.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, første læsning (de nyeste)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2009, første)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId: null) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h ORDER BY h.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, de næste læsninger (fra den højeste RECID, SQLInsight har læst, minus overlappet)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2009, næste)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId) via AxSql.InDatabase
|
||||
-- Agenten indsætter den højeste RECID, den har læst, minus overlappet, hvor der her står 0.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (3000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h WHERE h.[RECID] > 0 ORDER BY h.[RECID]';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(2012)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(j.[RECID] AS bigint), CAST(NULL AS int), j.[CAPTION], j.[COMPANY], CAST(NULL AS nvarchar(20)), j.[STATUS], j.[ORIGSTARTDATETIME], CAST(NULL AS int), j.[STARTDATETIME], CAST(NULL AS int), j.[ENDDATETIME], CAST(NULL AS int), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOB] j ORDER BY j.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, første læsning (de nyeste)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2012, første)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId: null) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h ORDER BY h.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, de næste læsninger (fra den højeste RECID, SQLInsight har læst, minus overlappet)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2012, næste)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId) via AxSql.InDatabase
|
||||
-- Agenten indsætter den højeste RECID, den har læst, minus overlappet, hvor der her står 0.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (3000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h WHERE h.[RECID] > 0 ORDER BY h.[RECID]';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AX-003: Dynamics AX-batchjob er ikke startet til tiden
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AX-003
|
||||
-- Titel: Dynamics AX-batchjob er ikke startet til tiden
|
||||
-- Alvor: Medium; High, når jobbet i praksis aldrig er startet.
|
||||
-- Versioner: SQL Server 2005 og nyere (ikke 2000). Axapta 3.0: verificeret mod en kundes skema (docs/dynamics-ax/
|
||||
-- schema-ax30.tsv). AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Et ventende batchjob, hvis planlagte start er passeret: batchserveren (AOS med batch, eller batch-klienten i
|
||||
-- Axapta 3.0) tager det ikke. Mange forsinkede job på én gang betyder typisk, at batchserveren slet ikke kører.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For job med status Venter: forsinkelse = nu - planlagt start. Planlagt start er i AX 2009+ BATCHJOB.ORIGSTARTDATETIME
|
||||
-- (UTC). I Axapta 3.0/4.0 er den BATCH.STARTDATE (lokal dato) + STARTTIME (sekunder efter midnat, lokal tid); den
|
||||
-- regnes om til UTC med AX-tidszonen (SQLInsight:DynamicsAx:LocalTimeZone, ellers agentens tidszone) og de
|
||||
-- sommertidsregler, der gjaldt på datoen. AX' tomme dato (1900-01-01) er "ingen". Job med status Tilbageholdt er
|
||||
-- ikke forsinkede. De mest forsinkede først.
|
||||
-- STATUS oversættes af versionens adapter: AX 2009+ 0 Tilbageholdt, 1 Venter, 2 Udfører, 3 Fejl, 4 Afsluttet,
|
||||
-- 5 Klar, 6 Ikke kørt, 7 Annullerer, 8 Annulleret; Axapta 3.0/4.0 samme rækkefølge: 0 Tilbageholdt, 1 Venter,
|
||||
-- 2 Udfører, 3 Fejl, 4 Afsluttet (1 og 4 kontrolleret mod kundedata 2026-10-03). Højst 25 fund pr. database.
|
||||
-- Job planlagt for mere end BatchAbandonedDays siden regnes som opgivne rækker og meldes ikke.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:DynamicsAx:BatchLateMinutes = 30: forsinket mere end så mange minutter: Medium
|
||||
-- SQLInsight:DynamicsAx:BatchNeverStartedHours = 24: forsinket mere end så mange timer: High, "aldrig startet"
|
||||
-- SQLInsight:DynamicsAx:BatchAbandonedDays = 30: planlagt for mere end så mange dage siden: opgivet, ingen fund
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql og grant-dynamics-ax-read.sql):
|
||||
-- Valgfri AX-læseadgang, kun SELECT (db/permissions/grant-dynamics-ax-read.sql; [bruger] = agentens databasebruger):
|
||||
-- Axapta 3.0: GRANT SELECT ON [bmssa].[BATCH] TO [bruger];
|
||||
-- AX 4.0: GRANT SELECT ON [dbo].[BATCH] TO [bruger];
|
||||
-- AX 2009/2012/F&O: GRANT SELECT ON [dbo].[BATCHJOB] TO [bruger];
|
||||
-- GRANT SELECT ON [dbo].[BATCHJOBHISTORY] TO [bruger];
|
||||
-- Mangler den, er reglen "ikke målbar" med den nøjagtige GRANT for databasen (også under Dynamics AX → AX-databaser
|
||||
-- og GET /api/v1/dynamics-ax/grant-script). Uden GRANT ændres intet.
|
||||
-- Genkendelsen: kun grant-least-privilege.sql (VIEW ANY DEFINITION; CONNECT ANY DATABASE fra 2014, ellers en
|
||||
-- databasebruger: CREATE USER [agent] FOR LOGIN [agent];).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.sql
|
||||
-- AxBatchCollector
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxBatchCollector.cs; SQL: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs
|
||||
-- Medlemmer: AxSchemaAdapter.BatchJobs(database), AxSchemaAdapter.BatchHistory(database, afterRecId), AxSql.InDatabase
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:dynamics-ax-batch)
|
||||
-- Delt script: SQL Scripts/_collectors/AxBatchCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/DynamicsAx/DynamicsAxRules.cs : AxBatchLateRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT med TOP og SET-sessionsindstillinger. AX-tabellerne læses i AX-databasen via
|
||||
-- [db].sys.sp_executesql (sessionen skifter aldrig database) under READ COMMITTED med SET LOCK_TIMEOUT 2000
|
||||
-- (SNAPSHOT, når databasen tillader det), aldrig NOLOCK; bagefter sættes agentens sessionsindstillinger
|
||||
-- igen. Intet ændrer data, indstillinger eller objekter. Kun i databaser genkendt som AX og valgt til
|
||||
-- overvågning.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); varianter for andre AX-versioner end din fejler eller giver ingen rækker - det er forventet.
|
||||
-- AX-forespørgslerne er vist for databasen AXDB: ret [AXDB] til din AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke overvågede databaser er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxBatchCollector: Batchjob og kørselshistorik i AX-databasen (valgfri AX-læseadgang)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Axapta 3.0 (skema bmssa, verificeret mod kundedata): batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(3.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(b.[RECID] AS bigint), b.[CLASSNUM], CAST(NULL AS nvarchar(60)), b.[COMPANY], b.[GROUPID], b.[STATUS], b.[STARTDATE], b.[STARTTIME], CAST(NULL AS datetime), CAST(NULL AS int), b.[ENDDATE], b.[ENDTIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [bmssa].[BATCH] b ORDER BY b.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 4.0 (skema dbo) - ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(4.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(b.[RECID] AS bigint), b.[CLASSNUM], CAST(NULL AS nvarchar(60)), b.[COMPANY], b.[GROUPID], b.[STATUS], b.[STARTDATE], b.[STARTTIME], CAST(NULL AS datetime), CAST(NULL AS int), b.[ENDDATE], b.[ENDTIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCH] b ORDER BY b.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(2009)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(j.[RECID] AS bigint), CAST(NULL AS int), j.[CAPTION], j.[COMPANY], CAST(NULL AS nvarchar(20)), j.[STATUS], j.[ORIGSTARTDATETIME], CAST(NULL AS int), j.[STARTDATETIME], CAST(NULL AS int), j.[ENDDATETIME], CAST(NULL AS int), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOB] j ORDER BY j.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, første læsning (de nyeste)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2009, første)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId: null) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h ORDER BY h.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, de næste læsninger (fra den højeste RECID, SQLInsight har læst, minus overlappet)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2009, næste)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId) via AxSql.InDatabase
|
||||
-- Agenten indsætter den højeste RECID, den har læst, minus overlappet, hvor der her står 0.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (3000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h WHERE h.[RECID] > 0 ORDER BY h.[RECID]';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(2012)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(j.[RECID] AS bigint), CAST(NULL AS int), j.[CAPTION], j.[COMPANY], CAST(NULL AS nvarchar(20)), j.[STATUS], j.[ORIGSTARTDATETIME], CAST(NULL AS int), j.[STARTDATETIME], CAST(NULL AS int), j.[ENDDATETIME], CAST(NULL AS int), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOB] j ORDER BY j.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, første læsning (de nyeste)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2012, første)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId: null) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h ORDER BY h.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, de næste læsninger (fra den højeste RECID, SQLInsight har læst, minus overlappet)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2012, næste)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId) via AxSql.InDatabase
|
||||
-- Agenten indsætter den højeste RECID, den har læst, minus overlappet, hvor der her står 0.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (3000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h WHERE h.[RECID] > 0 ORDER BY h.[RECID]';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AX-004: Dynamics AX-batchjob hænger i Udfører
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AX-004
|
||||
-- Titel: Dynamics AX-batchjob hænger i Udfører
|
||||
-- Alvor: High
|
||||
-- Versioner: SQL Server 2005 og nyere (ikke 2000). Axapta 3.0: verificeret mod en kundes skema (docs/dynamics-ax/
|
||||
-- schema-ax30.tsv). AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Et batchjob har haft status Udfører i flere timer. Typisk er AOS'en eller batch-klienten genstartet eller gået ned
|
||||
-- midt i kørslen, så jobbet aldrig blev afsluttet: det står som kørende, intet sker, og gentagne job planlægges ikke
|
||||
-- igen.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For job med status Udfører: kørt = nu - faktisk start (AX 2009+: BATCHJOB.STARTDATETIME; Axapta 3.0/4.0: første
|
||||
-- gang, SQLInsight så jobbet køre, så det kan have kørt længere). Fund, når kørt >= BatchStuckHours, medmindre jobbet
|
||||
-- efter sin egen historik (insight.AxBatchRuns, mindst BatchHistoryMinimumRuns kørsler) normalt kører så længe
|
||||
-- (kørt <= faktor x 90 %-fraktil).
|
||||
-- STATUS oversættes af versionens adapter: AX 2009+ 0 Tilbageholdt, 1 Venter, 2 Udfører, 3 Fejl, 4 Afsluttet,
|
||||
-- 5 Klar, 6 Ikke kørt, 7 Annullerer, 8 Annulleret; Axapta 3.0/4.0 samme rækkefølge (1 og 4 kontrolleret mod kundedata 2026-10-03):
|
||||
-- 0 Tilbageholdt, 1 Venter, 2 Udfører, 3 Fejl, 4 Afsluttet. Højst 25 fund pr. database.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:DynamicsAx:BatchStuckHours = 6: kørt mindst så mange timer
|
||||
-- SQLInsight:DynamicsAx:BatchLongRunningFactor = 2.0: ...og mere end så mange gange jobbets 90 %-fraktil, når der er
|
||||
-- historik
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql og grant-dynamics-ax-read.sql):
|
||||
-- Valgfri AX-læseadgang, kun SELECT (db/permissions/grant-dynamics-ax-read.sql; [bruger] = agentens databasebruger):
|
||||
-- Axapta 3.0: GRANT SELECT ON [bmssa].[BATCH] TO [bruger];
|
||||
-- AX 4.0: GRANT SELECT ON [dbo].[BATCH] TO [bruger];
|
||||
-- AX 2009/2012/F&O: GRANT SELECT ON [dbo].[BATCHJOB] TO [bruger];
|
||||
-- GRANT SELECT ON [dbo].[BATCHJOBHISTORY] TO [bruger];
|
||||
-- Mangler den, er reglen "ikke målbar" med den nøjagtige GRANT for databasen (også under Dynamics AX → AX-databaser
|
||||
-- og GET /api/v1/dynamics-ax/grant-script). Uden GRANT ændres intet.
|
||||
-- Genkendelsen: kun grant-least-privilege.sql (VIEW ANY DEFINITION; CONNECT ANY DATABASE fra 2014, ellers en
|
||||
-- databasebruger: CREATE USER [agent] FOR LOGIN [agent];).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.sql
|
||||
-- AxBatchCollector
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxBatchCollector.cs; SQL: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs
|
||||
-- Medlemmer: AxSchemaAdapter.BatchJobs(database), AxSchemaAdapter.BatchHistory(database, afterRecId), AxSql.InDatabase
|
||||
-- Interval: 5 min som standard (SQLInsight:CollectorIntervals:dynamics-ax-batch)
|
||||
-- Delt script: SQL Scripts/_collectors/AxBatchCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/DynamicsAx/DynamicsAxRules.cs : AxBatchStuckRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT med TOP og SET-sessionsindstillinger. AX-tabellerne læses i AX-databasen via
|
||||
-- [db].sys.sp_executesql (sessionen skifter aldrig database) under READ COMMITTED med SET LOCK_TIMEOUT 2000
|
||||
-- (SNAPSHOT, når databasen tillader det), aldrig NOLOCK; bagefter sættes agentens sessionsindstillinger
|
||||
-- igen. Intet ændrer data, indstillinger eller objekter. Kun i databaser genkendt som AX og valgt til
|
||||
-- overvågning.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); varianter for andre AX-versioner end din fejler eller giver ingen rækker - det er forventet.
|
||||
-- AX-forespørgslerne er vist for databasen AXDB: ret [AXDB] til din AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke overvågede databaser er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxBatchCollector: Batchjob og kørselshistorik i AX-databasen (valgfri AX-læseadgang)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Axapta 3.0 (skema bmssa, verificeret mod kundedata): batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(3.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(b.[RECID] AS bigint), b.[CLASSNUM], CAST(NULL AS nvarchar(60)), b.[COMPANY], b.[GROUPID], b.[STATUS], b.[STARTDATE], b.[STARTTIME], CAST(NULL AS datetime), CAST(NULL AS int), b.[ENDDATE], b.[ENDTIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [bmssa].[BATCH] b ORDER BY b.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 4.0 (skema dbo) - ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(4.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(b.[RECID] AS bigint), b.[CLASSNUM], CAST(NULL AS nvarchar(60)), b.[COMPANY], b.[GROUPID], b.[STATUS], b.[STARTDATE], b.[STARTTIME], CAST(NULL AS datetime), CAST(NULL AS int), b.[ENDDATE], b.[ENDTIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCH] b ORDER BY b.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(2009)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(j.[RECID] AS bigint), CAST(NULL AS int), j.[CAPTION], j.[COMPANY], CAST(NULL AS nvarchar(20)), j.[STATUS], j.[ORIGSTARTDATETIME], CAST(NULL AS int), j.[STARTDATETIME], CAST(NULL AS int), j.[ENDDATETIME], CAST(NULL AS int), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOB] j ORDER BY j.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, første læsning (de nyeste)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2009, første)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId: null) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h ORDER BY h.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, de næste læsninger (fra den højeste RECID, SQLInsight har læst, minus overlappet)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2009, næste)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId) via AxSql.InDatabase
|
||||
-- Agenten indsætter den højeste RECID, den har læst, minus overlappet, hvor der her står 0.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (3000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h WHERE h.[RECID] > 0 ORDER BY h.[RECID]';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: batchjob
|
||||
-- Kilde: AxSchemaAdapter.BatchJobs(2012)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(j.[RECID] AS bigint), CAST(NULL AS int), j.[CAPTION], j.[COMPANY], CAST(NULL AS nvarchar(20)), j.[STATUS], j.[ORIGSTARTDATETIME], CAST(NULL AS int), j.[STARTDATETIME], CAST(NULL AS int), j.[ENDDATETIME], CAST(NULL AS int), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOB] j ORDER BY j.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, første læsning (de nyeste)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2012, første)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId: null) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (1000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h ORDER BY h.[RECID] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: kørselshistorik, de næste læsninger (fra den højeste RECID, SQLInsight har læst, minus overlappet)
|
||||
-- Kilde: AxSchemaAdapter.BatchHistory(2012, næste)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.BatchHistory(database, afterRecId) via AxSql.InDatabase
|
||||
-- Agenten indsætter den højeste RECID, den har læst, minus overlappet, hvor der her står 0.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (3000) CAST(h.[RECID] AS bigint), CAST(h.[BATCHJOBID] AS bigint), h.[CAPTION], h.[COMPANY], h.[STATUS], h.[STARTDATETIME], h.[ENDDATETIME], DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[BATCHJOBHISTORY] h WHERE h.[RECID] > 0 ORDER BY h.[RECID]';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AX-005: Dynamics AX-nummerserie er ved at løbe tør
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AX-005
|
||||
-- Titel: Dynamics AX-nummerserie er ved at løbe tør
|
||||
-- Alvor: Medium; High over den kritiske procent eller inden for de kritiske dage; Critical, når serien er opbrugt.
|
||||
-- Versioner: SQL Server 2005 og nyere (ikke 2000). Axapta 3.0: verificeret mod en kundes skema (docs/dynamics-ax/
|
||||
-- schema-ax30.tsv). AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Når en nummerserie er brugt op, kan AX ikke tildele flere numre: oprettelse eller bogføring af fx ordrer, fakturaer
|
||||
-- eller posteringer, der bruger serien, fejler for alle brugere.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Grænse = HIGHEST, eller formatets kapacitet (10^antal # - 1), hvis den er lavere. Brugt % = (NEXTREC - LOWEST) /
|
||||
-- (grænse - LOWEST + 1). Tilbage = grænse - NEXTREC + 1. Prognose: forbrug pr. dag = (NEXTREC nu - NEXTREC i den
|
||||
-- ældste daglige måling i vinduet) / dage imellem; dage tilbage = (grænse - NEXTREC) / forbrug pr. dag. Målingerne er
|
||||
-- SQLInsights egne (insight.AxSequenceSamples, én pr. serie pr. dag). Manuelle, cykliske og spærrede serier springes
|
||||
-- over. Højst 25 fund pr. database. Tal: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : Interpret, AxForecast.From.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:DynamicsAx:NumberSequenceWarnPercent = 80: brugt mindst så mange procent: Medium
|
||||
-- SQLInsight:DynamicsAx:NumberSequenceCriticalPercent = 95: High
|
||||
-- SQLInsight:DynamicsAx:ForecastWarnDays = 90: løber tør inden for så mange dage efter prognosen: Medium
|
||||
-- SQLInsight:DynamicsAx:ForecastCriticalDays = 30: High
|
||||
-- SQLInsight:DynamicsAx:ForecastBasisDays = 30: prognosen bruger den ældste daglige måling inden for så mange dage
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql og grant-dynamics-ax-read.sql):
|
||||
-- Valgfri AX-læseadgang, kun SELECT (db/permissions/grant-dynamics-ax-read.sql; [bruger] = agentens databasebruger):
|
||||
-- Axapta 3.0: GRANT SELECT ON [bmssa].[NUMBERSEQUENCETABLE] TO [bruger];
|
||||
-- GRANT SELECT ON [bmssa].[NUMBERSEQUENCEREFERENCE] TO [bruger]; -- valgfri: om serien bruges
|
||||
-- AX 4.0/2009: de samme tabeller i [dbo]
|
||||
-- AX 2012/F&O: desuden GRANT SELECT ON [dbo].[NUMBERSEQUENCESCOPE] TO [bruger]; -- valgfri: firma
|
||||
-- Mangler NUMBERSEQUENCETABLE, er reglen "ikke målbar" med den nøjagtige GRANT for databasen. Uden GRANT ændres intet.
|
||||
-- Genkendelsen: kun grant-least-privilege.sql (VIEW ANY DEFINITION; CONNECT ANY DATABASE fra 2014, ellers en
|
||||
-- databasebruger: CREATE USER [agent] FOR LOGIN [agent];).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.sql
|
||||
-- AxSequenceCollector
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxSequenceCollector.cs; SQL: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs
|
||||
-- Medlemmer: AxSchemaAdapter.NumberSequences(database), AxSchemaAdapter.RecIds(database), AxSql.InDatabase
|
||||
-- Interval: 1 time som standard (SQLInsight:CollectorIntervals:dynamics-ax-sequences)
|
||||
-- Delt script: SQL Scripts/_collectors/AxSequenceCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/DynamicsAx/DynamicsAxRules.cs : AxNumberSequenceExhaustionRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT med TOP og SET-sessionsindstillinger. AX-tabellerne læses i AX-databasen via
|
||||
-- [db].sys.sp_executesql (sessionen skifter aldrig database) under READ COMMITTED med SET LOCK_TIMEOUT 2000
|
||||
-- (SNAPSHOT, når databasen tillader det), aldrig NOLOCK; bagefter sættes agentens sessionsindstillinger
|
||||
-- igen. Intet ændrer data, indstillinger eller objekter. Kun i databaser genkendt som AX og valgt til
|
||||
-- overvågning.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); varianter for andre AX-versioner end din fejler eller giver ingen rækker - det er forventet.
|
||||
-- AX-forespørgslerne er vist for databasen AXDB: ret [AXDB] til din AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke overvågede databaser er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxSequenceCollector: Nummerserier i AX-databasen (valgfri AX-læseadgang)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Axapta 3.0 (skema bmssa, verificeret mod kundedata): nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(3.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [bmssa].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATE], n.[LATESTCLEANTIME], CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [bmssa].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 4.0 (skema dbo) - ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(4.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATE], n.[LATESTCLEANTIME], CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(2009)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATETIME], CAST(NULL AS int), CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(2012)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], NULLIF(sc.[DATAAREA], N''''), n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCEID] = n.[RECID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATETIME], CAST(NULL AS int), CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n LEFT JOIN [dbo].[NUMBERSEQUENCESCOPE] sc ON sc.[RECID] = n.[NUMBERSEQUENCESCOPE] ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AX-006: Dynamics AX-nummerseriens format er for kort til Højeste
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AX-006
|
||||
-- Titel: Dynamics AX-nummerseriens format er for kort til Højeste
|
||||
-- Alvor: Medium; High, når NEXTREC allerede er større end formatets kapacitet.
|
||||
-- Versioner: SQL Server 2005 og nyere (ikke 2000). Axapta 3.0: verificeret mod en kundes skema (docs/dynamics-ax/
|
||||
-- schema-ax30.tsv). AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Formatet (fx "FA-####") har færre cifre, end HIGHEST kræver. Når serien når forbi formatets kapacitet, fejler
|
||||
-- tildelingen af numre, selv om serien ikke er brugt op.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Kapacitet = 10^(antal # i FORMAT) - 1. Fund, når HIGHEST > kapacitet (ikke for manuelle eller spærrede serier). High,
|
||||
-- når også NEXTREC > kapacitet. Højst 25 fund pr. database.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle: ren sammenligning.
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql og grant-dynamics-ax-read.sql):
|
||||
-- Valgfri AX-læseadgang, kun SELECT (db/permissions/grant-dynamics-ax-read.sql; [bruger] = agentens databasebruger):
|
||||
-- Axapta 3.0: GRANT SELECT ON [bmssa].[NUMBERSEQUENCETABLE] TO [bruger];
|
||||
-- GRANT SELECT ON [bmssa].[NUMBERSEQUENCEREFERENCE] TO [bruger]; -- valgfri: om serien bruges
|
||||
-- AX 4.0/2009: de samme tabeller i [dbo]
|
||||
-- AX 2012/F&O: desuden GRANT SELECT ON [dbo].[NUMBERSEQUENCESCOPE] TO [bruger]; -- valgfri: firma
|
||||
-- Mangler NUMBERSEQUENCETABLE, er reglen "ikke målbar" med den nøjagtige GRANT for databasen. Uden GRANT ændres intet.
|
||||
-- Genkendelsen: kun grant-least-privilege.sql (VIEW ANY DEFINITION; CONNECT ANY DATABASE fra 2014, ellers en
|
||||
-- databasebruger: CREATE USER [agent] FOR LOGIN [agent];).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.sql
|
||||
-- AxSequenceCollector
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxSequenceCollector.cs; SQL: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs
|
||||
-- Medlemmer: AxSchemaAdapter.NumberSequences(database), AxSchemaAdapter.RecIds(database), AxSql.InDatabase
|
||||
-- Interval: 1 time som standard (SQLInsight:CollectorIntervals:dynamics-ax-sequences)
|
||||
-- Delt script: SQL Scripts/_collectors/AxSequenceCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/DynamicsAx/DynamicsAxRules.cs : AxNumberSequenceFormatRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT med TOP og SET-sessionsindstillinger. AX-tabellerne læses i AX-databasen via
|
||||
-- [db].sys.sp_executesql (sessionen skifter aldrig database) under READ COMMITTED med SET LOCK_TIMEOUT 2000
|
||||
-- (SNAPSHOT, når databasen tillader det), aldrig NOLOCK; bagefter sættes agentens sessionsindstillinger
|
||||
-- igen. Intet ændrer data, indstillinger eller objekter. Kun i databaser genkendt som AX og valgt til
|
||||
-- overvågning.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); varianter for andre AX-versioner end din fejler eller giver ingen rækker - det er forventet.
|
||||
-- AX-forespørgslerne er vist for databasen AXDB: ret [AXDB] til din AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke overvågede databaser er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxSequenceCollector: Nummerserier i AX-databasen (valgfri AX-læseadgang)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Axapta 3.0 (skema bmssa, verificeret mod kundedata): nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(3.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [bmssa].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATE], n.[LATESTCLEANTIME], CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [bmssa].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 4.0 (skema dbo) - ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(4.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATE], n.[LATESTCLEANTIME], CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(2009)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATETIME], CAST(NULL AS int), CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(2012)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], NULLIF(sc.[DATAAREA], N''''), n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCEID] = n.[RECID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATETIME], CAST(NULL AS int), CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n LEFT JOIN [dbo].[NUMBERSEQUENCESCOPE] sc ON sc.[RECID] = n.[NUMBERSEQUENCESCOPE] ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AX-007: Spærret Dynamics AX-nummerserie bruges stadig
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AX-007
|
||||
-- Titel: Spærret Dynamics AX-nummerserie bruges stadig
|
||||
-- Alvor: Medium
|
||||
-- Versioner: SQL Server 2005 og nyere (ikke 2000). Axapta 3.0: verificeret mod en kundes skema (docs/dynamics-ax/
|
||||
-- schema-ax30.tsv). AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Serien er spærret (BLOCKED = 1), men en nummerseriereference peger stadig på den. Alt i AX, der skal have et nummer
|
||||
-- fra den reference, fejler med en fejl om, at nummerserien er spærret.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Fund, når BLOCKED = 1 og der findes en NUMBERSEQUENCEREFERENCE til serien (Axapta 3.0/4.0/2009: samme NUMBERSEQUENCE
|
||||
-- og DATAAREAID; AX 2012/F&O: NUMBERSEQUENCEID = seriens RECID). Kan referencetabellen ikke læses, vides det ikke, og
|
||||
-- der gives intet fund. Højst 25 fund pr. database.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- Ingen konfigurationsnøgle.
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql og grant-dynamics-ax-read.sql):
|
||||
-- Valgfri AX-læseadgang, kun SELECT (db/permissions/grant-dynamics-ax-read.sql; [bruger] = agentens databasebruger):
|
||||
-- Axapta 3.0: GRANT SELECT ON [bmssa].[NUMBERSEQUENCETABLE] TO [bruger];
|
||||
-- GRANT SELECT ON [bmssa].[NUMBERSEQUENCEREFERENCE] TO [bruger]; -- valgfri: om serien bruges
|
||||
-- AX 4.0/2009: de samme tabeller i [dbo]
|
||||
-- AX 2012/F&O: desuden GRANT SELECT ON [dbo].[NUMBERSEQUENCESCOPE] TO [bruger]; -- valgfri: firma
|
||||
-- Mangler NUMBERSEQUENCETABLE, er reglen "ikke målbar" med den nøjagtige GRANT for databasen. Uden GRANT ændres intet.
|
||||
-- Genkendelsen: kun grant-least-privilege.sql (VIEW ANY DEFINITION; CONNECT ANY DATABASE fra 2014, ellers en
|
||||
-- databasebruger: CREATE USER [agent] FOR LOGIN [agent];).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.sql
|
||||
-- AxSequenceCollector
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxSequenceCollector.cs; SQL: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs
|
||||
-- Medlemmer: AxSchemaAdapter.NumberSequences(database), AxSchemaAdapter.RecIds(database), AxSql.InDatabase
|
||||
-- Interval: 1 time som standard (SQLInsight:CollectorIntervals:dynamics-ax-sequences)
|
||||
-- Delt script: SQL Scripts/_collectors/AxSequenceCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/DynamicsAx/DynamicsAxRules.cs : AxNumberSequenceBlockedRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT med TOP og SET-sessionsindstillinger. AX-tabellerne læses i AX-databasen via
|
||||
-- [db].sys.sp_executesql (sessionen skifter aldrig database) under READ COMMITTED med SET LOCK_TIMEOUT 2000
|
||||
-- (SNAPSHOT, når databasen tillader det), aldrig NOLOCK; bagefter sættes agentens sessionsindstillinger
|
||||
-- igen. Intet ændrer data, indstillinger eller objekter. Kun i databaser genkendt som AX og valgt til
|
||||
-- overvågning.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); varianter for andre AX-versioner end din fejler eller giver ingen rækker - det er forventet.
|
||||
-- AX-forespørgslerne er vist for databasen AXDB: ret [AXDB] til din AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke overvågede databaser er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxSequenceCollector: Nummerserier i AX-databasen (valgfri AX-læseadgang)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Axapta 3.0 (skema bmssa, verificeret mod kundedata): nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(3.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [bmssa].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATE], n.[LATESTCLEANTIME], CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [bmssa].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 4.0 (skema dbo) - ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(4.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATE], n.[LATESTCLEANTIME], CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(2009)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATETIME], CAST(NULL AS int), CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(2012)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], NULLIF(sc.[DATAAREA], N''''), n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCEID] = n.[RECID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATETIME], CAST(NULL AS int), CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n LEFT JOIN [dbo].[NUMBERSEQUENCESCOPE] sc ON sc.[RECID] = n.[NUMBERSEQUENCESCOPE] ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AX-008: Kontinuerlig Dynamics AX-nummerserie er ikke ryddet op
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AX-008
|
||||
-- Titel: Kontinuerlig Dynamics AX-nummerserie er ikke ryddet op
|
||||
-- Alvor: Low
|
||||
-- Versioner: SQL Server 2005 og nyere (ikke 2000). Axapta 3.0: verificeret mod en kundes skema (docs/dynamics-ax/
|
||||
-- schema-ax30.tsv). AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- En kontinuerlig serie må ikke have huller. Numre reserveret af afbrudte sessioner bliver liggende som optagede, til
|
||||
-- serien ryddes op; uden oprydning opstår huller og fejl, og serien bliver en flaskehals, fordi hver tildeling låser
|
||||
-- rækken i NUMBERSEQUENCETABLE, til transaktionen er færdig.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For kontinuerlige (CONTINUOUS = 1), ikke spærrede, ikke manuelle serier, der er taget i brug (NEXTREC > LOWEST):
|
||||
-- fund, når seneste oprydning er ældre end grænsen eller aldrig er sket (1900-01-01). Seneste oprydning er
|
||||
-- LATESTCLEANDATETIME (UTC) i AX 2009+, og LATESTCLEANDATE + LATESTCLEANTIME (lokal tid, sekunder efter midnat) i
|
||||
-- Axapta 3.0. Mangler kolonnen, gives intet fund. Højst 25 fund pr. database.
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- 7 dage (fast, AxNumberSequenceContinuousRule.MinimumDays), eller 2 x seriens eget CLEANINTERVAL (timer), hvis længere.
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql og grant-dynamics-ax-read.sql):
|
||||
-- Valgfri AX-læseadgang, kun SELECT (db/permissions/grant-dynamics-ax-read.sql; [bruger] = agentens databasebruger):
|
||||
-- Axapta 3.0: GRANT SELECT ON [bmssa].[NUMBERSEQUENCETABLE] TO [bruger];
|
||||
-- GRANT SELECT ON [bmssa].[NUMBERSEQUENCEREFERENCE] TO [bruger]; -- valgfri: om serien bruges
|
||||
-- AX 4.0/2009: de samme tabeller i [dbo]
|
||||
-- AX 2012/F&O: desuden GRANT SELECT ON [dbo].[NUMBERSEQUENCESCOPE] TO [bruger]; -- valgfri: firma
|
||||
-- Mangler NUMBERSEQUENCETABLE, er reglen "ikke målbar" med den nøjagtige GRANT for databasen. Uden GRANT ændres intet.
|
||||
-- Genkendelsen: kun grant-least-privilege.sql (VIEW ANY DEFINITION; CONNECT ANY DATABASE fra 2014, ellers en
|
||||
-- databasebruger: CREATE USER [agent] FOR LOGIN [agent];).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.sql
|
||||
-- AxSequenceCollector
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxSequenceCollector.cs; SQL: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs
|
||||
-- Medlemmer: AxSchemaAdapter.NumberSequences(database), AxSchemaAdapter.RecIds(database), AxSql.InDatabase
|
||||
-- Interval: 1 time som standard (SQLInsight:CollectorIntervals:dynamics-ax-sequences)
|
||||
-- Delt script: SQL Scripts/_collectors/AxSequenceCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/DynamicsAx/DynamicsAxRules.cs : AxNumberSequenceContinuousRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT med TOP og SET-sessionsindstillinger. AX-tabellerne læses i AX-databasen via
|
||||
-- [db].sys.sp_executesql (sessionen skifter aldrig database) under READ COMMITTED med SET LOCK_TIMEOUT 2000
|
||||
-- (SNAPSHOT, når databasen tillader det), aldrig NOLOCK; bagefter sættes agentens sessionsindstillinger
|
||||
-- igen. Intet ændrer data, indstillinger eller objekter. Kun i databaser genkendt som AX og valgt til
|
||||
-- overvågning.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); varianter for andre AX-versioner end din fejler eller giver ingen rækker - det er forventet.
|
||||
-- AX-forespørgslerne er vist for databasen AXDB: ret [AXDB] til din AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke overvågede databaser er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxSequenceCollector: Nummerserier i AX-databasen (valgfri AX-læseadgang)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Axapta 3.0 (skema bmssa, verificeret mod kundedata): nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(3.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [bmssa].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATE], n.[LATESTCLEANTIME], CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [bmssa].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 4.0 (skema dbo) - ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(4.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATE], n.[LATESTCLEANTIME], CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(2009)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], n.[DATAAREAID], n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCE] = n.[NUMBERSEQUENCE] AND r.[DATAAREAID] = n.[DATAAREAID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATETIME], CAST(NULL AS int), CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: nummerserier
|
||||
-- Kilde: AxSchemaAdapter.NumberSequences(2012)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (5000) CAST(n.[RECID] AS bigint), n.[NUMBERSEQUENCE], NULLIF(sc.[DATAAREA], N''''), n.[TXT], CAST(n.[LOWEST] AS bigint), CAST(n.[HIGHEST] AS bigint), CAST(n.[NEXTREC] AS bigint), n.[FORMAT], ISNULL(n.[BLOCKED], 0), ISNULL(n.[CONTINUOUS], 0), ISNULL(n.[CYCLIC], 0), ISNULL(n.[MANUAL], 0), CASE WHEN EXISTS (SELECT 1 FROM [dbo].[NUMBERSEQUENCEREFERENCE] r WHERE r.[NUMBERSEQUENCEID] = n.[RECID]) THEN 1 ELSE 0 END, n.[LATESTCLEANDATETIME], CAST(NULL AS int), CAST(n.[CLEANINTERVAL] AS float), DATEDIFF(minute, GETDATE(), GETUTCDATE()) FROM [dbo].[NUMBERSEQUENCETABLE] n LEFT JOIN [dbo].[NUMBERSEQUENCESCOPE] sc ON sc.[RECID] = n.[NUMBERSEQUENCESCOPE] ORDER BY (CAST(n.[NEXTREC] AS float) - n.[LOWEST]) / NULLIF(CAST(n.[HIGHEST] AS float) - n.[LOWEST], 0) DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AX-009: Dynamics AX RecId er ved at løbe tør
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AX-009
|
||||
-- Titel: Dynamics AX RecId er ved at løbe tør
|
||||
-- Alvor: Axapta 3.0 (32-bit): High fra advarselsgrænsen, Critical fra den kritiske grænse; 64-bit: High; altid Critical, når RecId er opbrugt.
|
||||
-- Versioner: SQL Server 2005 og nyere (ikke 2000). Axapta 3.0: verificeret mod en kundes skema (docs/dynamics-ax/
|
||||
-- schema-ax30.tsv). AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Når en tabels RecId-serie er brugt op, kan AX ikke oprette flere poster. Axapta 3.0 har 32-bit RecId (int, højst
|
||||
-- 2.147.483.647 pr. tabel og firma), og det løses kun med et stort projekt - derfor advares langt tidligere for 3.0.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- Grænse = typens maksimum (int, når SYSTEMSEQUENCES.NEXTVAL er int som i Axapta 3.0; ellers bigint), eller MAXVAL,
|
||||
-- hvis den er sat lavere. Brugt % = NEXTVAL / grænse. Prognose ud fra SQLInsights egne daglige målinger af NEXTVAL
|
||||
-- (insight.AxSequenceSamples). Højst 25 fund pr. database, de mest brugte først. Tal: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : Interpret(AxRecIdRow).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:DynamicsAx:RecId32WarnPercent = 50: Axapta 3.0: High fra så mange procent af int-intervallet
|
||||
-- SQLInsight:DynamicsAx:RecId32CriticalPercent = 75: Axapta 3.0: Critical
|
||||
-- SQLInsight:DynamicsAx:RecId32ForecastDays = 730: Axapta 3.0: High, hvis den løber tør inden for så mange dage;
|
||||
-- Critical inden for halvdelen
|
||||
-- SQLInsight:DynamicsAx:RecId64WarnPercent = 80: 64-bit (eller sænket MAXVAL): High
|
||||
-- SQLInsight:DynamicsAx:ForecastWarnDays = 90: 64-bit: High, hvis den løber tør inden for så mange dage
|
||||
-- SQLInsight:DynamicsAx:ForecastBasisDays = 30: prognosen bruger den ældste daglige måling inden for så mange dage
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql og grant-dynamics-ax-read.sql):
|
||||
-- Valgfri AX-læseadgang, kun SELECT (db/permissions/grant-dynamics-ax-read.sql; [bruger] = agentens databasebruger):
|
||||
-- Axapta 3.0: GRANT SELECT ON [bmssa].[SYSTEMSEQUENCES] TO [bruger];
|
||||
-- GRANT SELECT ON [bmssa].[SQLDICTIONARY] TO [bruger]; -- valgfri: tabelnavne
|
||||
-- AX 4.0/2009/2012/F&O: de samme tabeller i [dbo]
|
||||
-- Mangler SYSTEMSEQUENCES, er reglen "ikke målbar" med den nøjagtige GRANT for databasen. Uden GRANT ændres intet.
|
||||
-- Genkendelsen: kun grant-least-privilege.sql (VIEW ANY DEFINITION; CONNECT ANY DATABASE fra 2014, ellers en
|
||||
-- databasebruger: CREATE USER [agent] FOR LOGIN [agent];).
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.sql
|
||||
-- AxSequenceCollector
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxSequenceCollector.cs; SQL: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs
|
||||
-- Medlemmer: AxSchemaAdapter.NumberSequences(database), AxSchemaAdapter.RecIds(database), AxSql.InDatabase
|
||||
-- Interval: 1 time som standard (SQLInsight:CollectorIntervals:dynamics-ax-sequences)
|
||||
-- Delt script: SQL Scripts/_collectors/AxSequenceCollector.sql
|
||||
-- Regelkode: src/SQLInsight.Rules/DynamicsAx/DynamicsAxRules.cs : AxRecIdExhaustionRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT med TOP og SET-sessionsindstillinger. AX-tabellerne læses i AX-databasen via
|
||||
-- [db].sys.sp_executesql (sessionen skifter aldrig database) under READ COMMITTED med SET LOCK_TIMEOUT 2000
|
||||
-- (SNAPSHOT, når databasen tillader det), aldrig NOLOCK; bagefter sættes agentens sessionsindstillinger
|
||||
-- igen. Intet ændrer data, indstillinger eller objekter. Kun i databaser genkendt som AX og valgt til
|
||||
-- overvågning.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); varianter for andre AX-versioner end din fejler eller giver ingen rækker - det er forventet.
|
||||
-- AX-forespørgslerne er vist for databasen AXDB: ret [AXDB] til din AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke overvågede databaser er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxSequenceCollector: RecId pr. tabel og firma i AX-databasen (valgfri AX-læseadgang)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Axapta 3.0 (skema bmssa, verificeret mod kundedata): RecId pr. tabel (SYSTEMSEQUENCES)
|
||||
-- Kilde: AxSchemaAdapter.RecIds(3.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.RecIds(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (500) s.[TABID], s.[DATAAREAID], CAST(s.[NEXTVAL] AS bigint), CAST(s.[MAXVAL] AS bigint), (SELECT TOP 1 d.[NAME] FROM [bmssa].[SQLDICTIONARY] d WHERE d.[TABLEID] = s.[TABID] AND d.[FIELDID] = 0) FROM [bmssa].[SYSTEMSEQUENCES] s WHERE s.[NAME] = N''SEQNO'' ORDER BY s.[NEXTVAL] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 4.0 (skema dbo) - ikke verificeret mod kundedata: RecId pr. tabel (SYSTEMSEQUENCES)
|
||||
-- Kilde: AxSchemaAdapter.RecIds(4.0)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.RecIds(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (500) s.[TABID], s.[DATAAREAID], CAST(s.[NEXTVAL] AS bigint), CAST(s.[MAXVAL] AS bigint), (SELECT TOP 1 d.[NAME] FROM [dbo].[SQLDICTIONARY] d WHERE d.[TABLEID] = s.[TABID] AND d.[FIELDID] = 0) FROM [dbo].[SYSTEMSEQUENCES] s WHERE s.[NAME] = N''SEQNO'' ORDER BY s.[NEXTVAL] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: RecId pr. tabel (SYSTEMSEQUENCES)
|
||||
-- Kilde: AxSchemaAdapter.RecIds(2009)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.RecIds(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (500) s.[TABID], s.[DATAAREAID], CAST(s.[NEXTVAL] AS bigint), CAST(s.[MAXVAL] AS bigint), (SELECT TOP 1 d.[NAME] FROM [dbo].[SQLDICTIONARY] d WHERE d.[TABLEID] = s.[TABID] AND d.[FIELDID] = 0) FROM [dbo].[SYSTEMSEQUENCES] s WHERE s.[NAME] = N''SEQNO'' ORDER BY s.[NEXTVAL] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: RecId pr. tabel (SYSTEMSEQUENCES)
|
||||
-- Kilde: AxSchemaAdapter.RecIds(2012)
|
||||
-- Kode: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs : AxSchemaAdapter.RecIds(database) via AxSql.InDatabase
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT TOP (500) s.[TABID], s.[DATAAREAID], CAST(s.[NEXTVAL] AS bigint), CAST(s.[MAXVAL] AS bigint), (SELECT TOP 1 d.[NAME] FROM [dbo].[SQLDICTIONARY] d WHERE d.[TABLEID] = s.[TABID] AND d.[FIELDID] = 0) FROM [dbo].[SYSTEMSEQUENCES] s WHERE s.[NAME] = N''SEQNO'' ORDER BY s.[NEXTVAL] DESC';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-AX-010: AX-bruger blokerer andre
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-AX-010
|
||||
-- Titel: AX-bruger blokerer andre
|
||||
-- Alvor: Medium; High ved ventetid over 5 minutter eller mindst 10 blokerede sessioner.
|
||||
-- Versioner: Blokering: SQL Server 2000 og nyere; AX-genkendelsen og dermed reglen: SQL Server 2005 og nyere.
|
||||
-- Axapta 3.0/4.0: AX-brugeren kan ikke ses. AX 2009/2012/F&O: baseret på Microsofts dokumentation - ikke
|
||||
-- verificeret mod kundedata.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- En session i en Dynamics AX-database holder låse, som andre AX-brugere eller batchjob venter på. Alle AX-brugere går
|
||||
-- gennem AOS'ens login, så SQL Server-login'et siger ikke, hvem det er. Reglen viser AX-brugeren, når SQL Server kan
|
||||
-- se den.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke i SQL'en, medmindre andet er nævnt):
|
||||
-- For hver head blocker, hvis egen database eller en blokeret sessions database er genkendt som AX: fund, når den
|
||||
-- længste ventetid i kæden er over grænsen. AX 2009/2012/F&O: AX-brugeren og AX-sessionen læses fra CONTEXT_INFO,
|
||||
-- som AOS'en sætter, når "connectioncontext" er slået til i AOS-konfigurationen (formatet er dokumenteret af
|
||||
-- Microsoft for AX 2012 - ikke verificeret mod kundedata). Axapta 3.0 og AX 4.0 sætter aldrig CONTEXT_INFO:
|
||||
-- brugeren kan ikke ses fra SQL Server, og fundet siger det ærligt. AX-bruger, vært, program og CONTEXT_INFO er
|
||||
-- følsomme målinger (sendes ikke til SQLInsight Hub uden SendSensitiveEvidence). Brugeren findes af
|
||||
-- src/SQLInsight.Core/DynamicsAx/AxSessionMapper.cs. AX-tabeller læses ikke (og aldrig med NOLOCK).
|
||||
--
|
||||
-- Grænseværdier (konfigurationsnøgle i agentens appsettings.json og standardværdi):
|
||||
-- SQLInsight:DynamicsAx:BlockingSeconds = 30: den længste ventetid bag sessionen skal være mindst så mange sekunder.
|
||||
-- High fra 300.000 ms eller 10 blokerede (fast i koden, som SQLI-BLK-001).
|
||||
--
|
||||
-- Rettigheder til agentens login (se db/permissions/grant-least-privilege.sql og grant-dynamics-ax-read.sql):
|
||||
-- Ingen AX-læseadgang: kun grant-least-privilege.sql.
|
||||
-- GRANT VIEW SERVER STATE TO [agent]; -- SQL Server 2005-2019 (sessionerne)
|
||||
-- GRANT VIEW SERVER PERFORMANCE STATE TO [agent]; -- SQL Server 2022+
|
||||
-- GRANT VIEW ANY DEFINITION TO [agent]; -- AX-genkendelsen (metadata)
|
||||
-- GRANT CONNECT ANY DATABASE TO [agent]; -- SQL Server 2014+; før 2014 en databasebruger i AX-databasen
|
||||
--
|
||||
-- Data kommer fra (collector, fil : medlemmer, interval):
|
||||
-- AxDatabaseDetector (den fælles AX-genkendelse)
|
||||
-- Fil: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs
|
||||
-- Medlemmer: AxDatabaseDetector.DatabasesSql, AxDatabaseDetector.BuildDetectionSql(database)
|
||||
-- Interval: hver time pr. database (hvert 5. minut, mens AX-læseadgangen mangler), delt af alle AX-collectors
|
||||
-- Delt script: SQL Scripts/_collectors/AxDatabaseDetector.sql
|
||||
-- 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/DynamicsAx/DynamicsAxRules.cs : AxBlockingUserRule
|
||||
--
|
||||
-- Read-only: Ja: kun SELECT med TOP og SET-sessionsindstillinger. AX-tabellerne læses i AX-databasen via
|
||||
-- [db].sys.sp_executesql (sessionen skifter aldrig database) under READ COMMITTED med SET LOCK_TIMEOUT 2000
|
||||
-- (SNAPSHOT, når databasen tillader det), aldrig NOLOCK; bagefter sættes agentens sessionsindstillinger
|
||||
-- igen. Intet ændrer data, indstillinger eller objekter. Kun i databaser genkendt som AX og valgt til
|
||||
-- overvågning.
|
||||
-- Kørsel: Kør i SSMS som agentens login (eller et login med samme rettigheder). Hver variant er sin egen batch
|
||||
-- (GO); varianter for andre AX-versioner end din fejler eller giver ingen rækker - det er forventet.
|
||||
-- AX-forespørgslerne er vist for databasen AXDB: ret [AXDB] til din AX-database.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- 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
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- AxDatabaseDetector: Hvilke overvågede databaser er Dynamics AX (kun metadata)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger
|
||||
-- Kilde: AxDatabaseDetector.DatabasesSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.DatabasesSql
|
||||
SELECT name, snapshot_isolation_state, is_read_committed_snapshot_on
|
||||
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: AX-genkendelsen i hver overvåget database (kun metadata; vist for AXDB)
|
||||
-- Kilde: AxDatabaseDetector.BuildDetectionSql
|
||||
-- Kode: src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs : AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)
|
||||
-- Agenten kører dette i hver overvåget database fra listen ovenfor (ikke *_model). Ret [AXDB] til den database, du vil tjekke.
|
||||
EXEC [AXDB].sys.sp_executesql N'SET NOCOUNT ON; SET LOCK_TIMEOUT 2000; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT s.name, UPPER(t.name), UPPER(c.name), TYPE_NAME(c.system_type_id), c.precision, c.max_length,
|
||||
ISNULL(HAS_PERMS_BY_NAME(QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name), N''OBJECT'', N''SELECT''), 0),
|
||||
(SELECT TOP 1 p.name FROM sys.database_principals p WHERE p.sid = SUSER_SID())
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
WHERE UPPER(t.name) IN (N''SQLDICTIONARY'', N''DATAAREA'', N''SYSCONFIG'', N''BATCH'', N''BATCHJOB'', N''BATCHJOBHISTORY'', N''BATCHGROUP'', N''NUMBERSEQUENCETABLE'', N''NUMBERSEQUENCESCOPE'', N''NUMBERSEQUENCEREFERENCE'', N''SYSTEMSEQUENCES'', N''MODELELEMENT'')
|
||||
ORDER BY s.name, t.name, c.column_id';
|
||||
SET LOCK_TIMEOUT 5000; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- BlockingCollector: Blokerede sessioner og deres blokerere lige nu, med sætning, åbne transaktioner og CONTEXT_INFO.
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- 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, s.context_info
|
||||
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 2008 – 2008 R2
|
||||
-- Kilde: BlockingCollector.BuildSql2005(2008)
|
||||
-- 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, s.context_info
|
||||
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 (CONTEXT_INFO fra sys.sysprocesses)
|
||||
-- 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, (SELECT TOP 1 p.context_info FROM sys.sysprocesses p WHERE p.spid = s.session_id AND p.ecid = 0)
|
||||
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, p.context_info
|
||||
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
|
||||
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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, s.context_info
|
||||
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 2008 – 2008 R2
|
||||
-- Kilde: BlockingCollector.BuildSql2005(2008)
|
||||
-- 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, s.context_info
|
||||
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 (CONTEXT_INFO fra sys.sysprocesses)
|
||||
-- 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, (SELECT TOP 1 p.context_info FROM sys.sysprocesses p WHERE p.spid = s.session_id AND p.ecid = 0)
|
||||
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, p.context_info
|
||||
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
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,222 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,247 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,299 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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: Ja: kun SELECT (sys.fn_xe_file_target_read_file og DMV'er) samt SET-sessionsindstillinger. Ingen
|
||||
-- temp-tabeller; læsepositionen findes med ROW_NUMBER() i samme forespørgsel.
|
||||
-- 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 e.event_data, e.file_name, e.file_offset, e.rn
|
||||
FROM (
|
||||
SELECT CASE WHEN object_name = N'xml_deadlock_report' THEN CAST(event_data AS nvarchar(max)) END AS event_data,
|
||||
file_name, file_offset,
|
||||
ROW_NUMBER() OVER (ORDER BY file_name DESC, file_offset DESC) AS rn
|
||||
FROM sys.fn_xe_file_target_read_file(N'system_health*.xel', NULL, NULL, NULL)
|
||||
) AS e
|
||||
WHERE e.event_data IS NOT NULL OR e.rn = 1;
|
||||
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
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,222 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- 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
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
-- ===================================================================================================================
|
||||
-- SQLI-SYN-001: Et syntetisk tjek fejler
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-SYN-001
|
||||
-- Titel: Et syntetisk tjek fejler
|
||||
-- Alvor: High.
|
||||
-- Versioner: SQL: SQL Server 2005 og nyere (SqlClient, ODBC-fallback for 2005). AX-logon: AX 2009 (kræver Windows PowerShell
|
||||
-- 2.0-motoren) og AX 2012. Windows-tjenester: Windows Server 2008 R2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, og hvorfor:
|
||||
-- Agenten gør det, en bruger eller applikation ville gøre – forbinder til en port, henter en side, logger på SQL Server
|
||||
-- og kører en forespørgsel, slår et navn op, logger på Dynamics AX – og det fejler. Er tjekket knyttet til en tjeneste
|
||||
-- på en Windows-server, og kører tjenesten, siges det direkte: "… svarer ikke, selv om tjenesten kører" – den fejl,
|
||||
-- en tjenesteovervågning alene ikke ser.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- Har de seneste FailuresBeforeFinding kørsler alle fejlet, er det et fund. Titlen siger, om den tilknyttede tjeneste
|
||||
-- kører, er stoppet (eller i en anden tilstand) eller ikke findes, eller at tjekket fejler N gange i træk. Fejlteksten
|
||||
-- står aldrig i titlen (den sendes uredigeret til API og notifikationer), kun som måling (følsom). Er alle de
|
||||
-- resultater, agenten har givet reglen, fejl, siges "mindst N" gange, og "Fejler siden" er "… eller tidligere".
|
||||
--
|
||||
-- Grænseværdier (agentens appsettings.json og tjekkets indstillinger):
|
||||
-- SQLInsight:SyntheticChecks:FailuresBeforeFinding standard 2 (fejl i træk før et fund: ét tabt svar er ingen alarm)
|
||||
-- Pr. tjek: interval (standard 300 s, 60–86400) og timeout (standard 15 s, AX 60 s, højst 120).
|
||||
--
|
||||
-- Rettigheder:
|
||||
-- TCP, HTTP(S), DNS: ingen ud over netværksadgang fra agentens server. HTTP med Windows-godkendelse: agentens konto.
|
||||
-- SQL: login'et i tjekket (agentens Windows-konto eller et SQL-login, hvis adgangskode krypteres til agenten som i 1.3)
|
||||
-- skal kunne logge ind og køre forespørgslen; least-privilege-login'et fra grant-least-privilege.sql er nok til standardforespørgslen.
|
||||
-- AX-logon: agentens Windows-konto skal være AX-bruger (i firmaet), og .NET Business Connector skal være installeret på
|
||||
-- agentens server; ellers testes kun AOS-porten (og resultatet siger det).
|
||||
-- Tjenestens tilstand: WMI Remote Enable på root\cimv2 + læseret på Service Control Manager på tjenestens server.
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs – SyntheticCheckRunner.RunAsync (TcpAsync, HttpAsync, SqlAsync,
|
||||
-- DnsAsync, AxAsync), AX-logon: src/SQLInsight.Servers/Synthetic/AxBusinessConnector.cs og ax-logon.ps1. Køres efter
|
||||
-- tjekkets interval af src/SQLInsight.Agent/Servers/SyntheticCheckService.cs – RunCheckAsync, som også slår den tilknyttede
|
||||
-- tjenestes tilstand op (CimQueries.SingleServiceQuery).
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/SyntheticCheckRules.cs : SyntheticCheckFailingRule
|
||||
--
|
||||
-- Read-only: Ja. Ved et SQL-tjek valideres forespørgslen som én skrivebeskyttet SELECT, både når tjekket gemmes og
|
||||
-- før hver kørsel (src/SQLInsight.Core/CustomRules/ReadOnlyQuery.cs), og den køres i en transaktion, der
|
||||
-- altid rulles tilbage. Andre typer tjek sender ingen SQL og ændrer intet.
|
||||
-- Kørsel: Kør i SSMS som tjekkets login. Hver GO er en separat kommando på samme forbindelse; ret [msdb] til
|
||||
-- tjekkets database, eller udelad USE, hvis tjekket ingen database har.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- SQL: Ved et SQL-tjek kører agenten præcis dette på den instans, tjekket peger på (ændrer intet: forespørgslen
|
||||
-- valideres som én skrivebeskyttet SELECT, både når den gemmes og før den køres, og køres i en transaktion, der altid
|
||||
-- rulles tilbage). Hver GO er en separat kommando på samme forbindelse.
|
||||
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- SyntheticCheckRunner: SQL-tjekket (login, sessionsindstillinger, forespørgslen i en transaktion, der rulles tilbage)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner (også tjekkets)
|
||||
-- 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
|
||||
|
||||
-- Variant: Kun når tjekket har en database (vist for msdb)
|
||||
-- Kilde: SyntheticCheckRunner.UseDatabaseSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.UseDatabaseSql(database)
|
||||
USE [msdb];
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: før forespørgslen
|
||||
-- Kilde: SyntheticCheckRunner.BeginTransactionSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.BeginTransactionSql
|
||||
BEGIN TRANSACTION;
|
||||
GO
|
||||
|
||||
-- Variant: Standardforespørgslen, når tjekket ikke har sin egen (en egen forespørgsel køres her i stedet, højst 10.000 rækker læses)
|
||||
-- Kilde: SyntheticCheckSettings.DefaultQuery
|
||||
-- Kode: src/SQLInsight.Core/SyntheticChecks/SyntheticCheckDefinitions.cs : SyntheticCheckSettings.DefaultQuery
|
||||
SELECT 1
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: altid efter forespørgslen, også når den fejler
|
||||
-- Kilde: SyntheticCheckRunner.RollbackSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.RollbackSql
|
||||
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
|
||||
GO
|
||||
|
||||
-- Ikke-SQL-tjek, efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
|
||||
-- TCP: Test-NetConnection -ComputerName aos01 -Port 2712
|
||||
-- HTTP: Invoke-WebRequest -Uri https://ep.firma.local/ -UseDefaultCredentials -UseBasicParsing | Select-Object StatusCode
|
||||
-- DNS: Resolve-DnsName aos01.firma.local
|
||||
-- AX: Test-NetConnection -ComputerName aos01 -Port 2712 (logon: se src/SQLInsight.Servers/Synthetic/ax-logon.ps1)
|
||||
-- Tjeneste: Get-CimInstance -ComputerName aos01 -Query "SELECT Name, DisplayName, State, StartMode, ExitCode FROM Win32_Service WHERE Name = 'AOS60`$01'"
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue