/* Regel: SQLI-AX-005 – Dynamics AX-nummerserie er ved at løbe tør Alvorlighed: Medium; Høj (High) over den kritiske procent eller inden for de kritiske dage; Kritisk (Critical), når serien er opbrugt Hvad 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. Tærskler (agentens konfiguration SQLInsight:DynamicsAx) NumberSequenceWarnPercent = 80 brugt mindst så mange procent: Medium NumberSequenceCriticalPercent = 95 …: Høj ForecastWarnDays = 90 løber tør inden for så mange dage efter prognosen: Medium ForecastCriticalDays = 30 …: Høj ForecastBasisDays = 30 prognosen bruger den ældste daglige måling inden for så mange dage (mindst 1 dag gammel) Vurdering (C#: src/SQLInsight.Rules/DynamicsAx/DynamicsAxRules.cs – AxNumberSequenceExhaustionRule; tal i src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs – Interpret og AxForecast.From) 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, gemt i HourlyDays = 400 dage). Manuelle, cykliske og spærrede serier springes over. Højst 25 fund pr. database. Collector: src/SQLInsight.Collectors/DynamicsAx/AxSequenceCollector.cs – AxSequenceCollector.CollectAsync (hver time). SQL: src/SQLInsight.Core/DynamicsAx/AxSchemaAdapter.cs – NumberSequences. Rettigheder: Valgfri AX-læseadgang, kun SELECT (db/permissions/grant-dynamics-ax-read.sql): Axapta 3.0: GRANT SELECT ON [bmssa].[NUMBERSEQUENCETABLE] TO []; GRANT SELECT ON [bmssa].[NUMBERSEQUENCEREFERENCE] TO []; (valgfri) AX 4.0/2009: samme tabeller i [dbo] AX 2012/F&O: GRANT SELECT ON [dbo].[NUMBERSEQUENCETABLE] TO []; GRANT SELECT ON [dbo].[NUMBERSEQUENCESCOPE] TO []; (valgfri: firma) GRANT SELECT ON [dbo].[NUMBERSEQUENCEREFERENCE] TO []; (valgfri) Mangler NUMBERSEQUENCETABLE, er reglen "ikke målbar" med den nøjagtige GRANT for databasen. Versioner: SQL Server 2005 og nyere (ikke 2000). Axapta 3.0: verificeret mod en kundes skema (schema-ax30.tsv). AX 4.0, AX 2009, AX 2012 og F&O: baseret på Microsofts dokumenterede skema – ikke verificeret mod kundedata. Læsning: Kun SELECT med TOP (de mest brugte først), READ COMMITTED med SET LOCK_TIMEOUT 2000 (SNAPSHOT, når databasen tillader det), aldrig NOLOCK, i AX-databasen via [db].sys.sp_executesql. Kun i databaser genkendt som AX og valgt til overvågning. */ -- >>> SQL, som SQLInsight kører – genereret fra koden (tests/SQLInsight.Collectors.Tests/SqlScriptTests.cs). Ret ikke herunder i hånden. -- Variant: Axapta 3.0 (skema bmssa): nummerserier (AxSchemaAdapter.NumberSequences) DECLARE @Database sysname; SET @Database = N'AXDB'; -- <== ret til AX-databasen DECLARE @Schema sysname; SET @Schema = N'bmssa'; -- <== ejeren af AX-tabellerne: bmssa i Axapta 3.0, ellers dbo DECLARE @Sql nvarchar(max); SET @Sql = 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 @Sql = REPLACE(@Sql, N'[bmssa].', QUOTENAME(@Schema) + N'.'); DECLARE @Procedure nvarchar(300); SET @Procedure = QUOTENAME(@Database) + N'.sys.sp_executesql'; EXEC @Procedure @Sql; SET LOCK_TIMEOUT -1; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; GO -- Variant: AX 4.0 (skema dbo) – ikke verificeret mod kundedata: nummerserier (AxSchemaAdapter.NumberSequences) DECLARE @Database sysname; SET @Database = N'AXDB'; -- <== ret til AX-databasen DECLARE @Schema sysname; SET @Schema = N'dbo'; -- <== ejeren af AX-tabellerne: bmssa i Axapta 3.0, ellers dbo DECLARE @Sql nvarchar(max); SET @Sql = 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 @Sql = REPLACE(@Sql, N'[dbo].', QUOTENAME(@Schema) + N'.'); DECLARE @Procedure nvarchar(300); SET @Procedure = QUOTENAME(@Database) + N'.sys.sp_executesql'; EXEC @Procedure @Sql; SET LOCK_TIMEOUT -1; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; GO -- Variant: AX 2009 – baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: nummerserier (AxSchemaAdapter.NumberSequences) DECLARE @Database sysname; SET @Database = N'AXDB'; -- <== ret til AX-databasen DECLARE @Schema sysname; SET @Schema = N'dbo'; -- <== ejeren af AX-tabellerne: bmssa i Axapta 3.0, ellers dbo DECLARE @Sql nvarchar(max); SET @Sql = 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 @Sql = REPLACE(@Sql, N'[dbo].', QUOTENAME(@Schema) + N'.'); DECLARE @Procedure nvarchar(300); SET @Procedure = QUOTENAME(@Database) + N'.sys.sp_executesql'; EXEC @Procedure @Sql; SET LOCK_TIMEOUT -1; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; GO -- Variant: AX 2012 RTM/R2/R3 og F&O – baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata: nummerserier (AxSchemaAdapter.NumberSequences) DECLARE @Database sysname; SET @Database = N'AXDB'; -- <== ret til AX-databasen DECLARE @Schema sysname; SET @Schema = N'dbo'; -- <== ejeren af AX-tabellerne: bmssa i Axapta 3.0, ellers dbo DECLARE @Sql nvarchar(max); SET @Sql = 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 @Sql = REPLACE(@Sql, N'[dbo].', QUOTENAME(@Schema) + N'.'); DECLARE @Procedure nvarchar(300); SET @Procedure = QUOTENAME(@Database) + N'.sys.sp_executesql'; EXEC @Procedure @Sql; SET LOCK_TIMEOUT -1; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; GO -- <<< slut på genereret SQL