sqlinsight-pro/tests/SQLInsight.Core.Tests/WaitSamplingTests.cs
Søren Eggert Lundsteen Olsen 20671bfb06 Wait type drill-down with active session sampling
A new light collector samples sys.dm_exec_requests every 15 seconds:
waiting user sessions (not the agent's own) by wait type, database and
statement (same key as top SQL), with blocking. Sampling-only cycles
reuse the last probe and skip rule evaluation. Stored in
insight.ActiveWaitSamples (migration 0010) for RawDays.

Wait types on the instance page and in the analysis link to
/instanser/{navn}/ventetyper/{type}: Danish explanation from a new
knowledge base (shared with the SQLI-WAIT rules, with Dynamics AX notes),
trend over time, the statements that waited with share and estimated
wait, a link to the full text (/instanser/{navn}/sql) and, for lock
waits, to blocking in the same window. SQL Server 2005 compatible.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 08:50:31 +02:00

68 lines
2.8 KiB
C#

using SQLInsight.Core.Data;
namespace SQLInsight.Core.Tests;
public class WaitSamplingTests
{
private static readonly DateTimeOffset Now = new(2026, 10, 2, 8, 0, 0, TimeSpan.Zero);
[Theory]
[InlineData("LCK_M_X", "LCK_M_*")]
[InlineData("lck_m_sch_m", "LCK_M_*")]
[InlineData("PAGEIOLATCH_SH", "PAGEIOLATCH_*")]
[InlineData("CXPACKET", "CXPACKET, CXCONSUMER, CXSYNC_*")]
[InlineData("CXSYNC_PORT", "CXPACKET, CXCONSUMER, CXSYNC_*")]
[InlineData("RESOURCE_SEMAPHORE_QUERY_COMPILE", "RESOURCE_SEMAPHORE_QUERY_COMPILE")]
[InlineData("RESOURCE_SEMAPHORE", "RESOURCE_SEMAPHORE")]
[InlineData("PREEMPTIVE_OS_AUTHENTICATIONOPS", "PREEMPTIVE_*")]
[InlineData("BACKUPBUFFER", "BACKUPIO, BACKUPBUFFER")]
[InlineData("LATCH_EX", "LATCH_*")]
public void Wait_types_find_their_family(string waitType, string family)
{
var explanation = WaitKnowledge.Lookup(waitType);
Assert.True(explanation.Known);
Assert.Equal(family, explanation.Family);
Assert.False(string.IsNullOrWhiteSpace(explanation.Actions));
}
[Fact]
public void Parallelism_mentions_maxdop_1_for_dynamics_ax_and_shares_the_rule_text()
{
var cx = WaitKnowledge.Lookup("CXPACKET");
Assert.Contains("MAXDOP 1", cx.DynamicsAx, StringComparison.Ordinal);
Assert.Same(WaitKnowledge.Parallelism, cx);
}
[Fact]
public void Unknown_wait_types_get_a_generic_text_with_their_category()
{
var unknown = WaitKnowledge.Lookup("SOME_NEW_WAIT_2027");
Assert.False(unknown.Known);
Assert.Contains("SOME_NEW_WAIT_2027", unknown.Meaning, StringComparison.Ordinal);
Assert.Equal("Baggrundsventetid uden betydning", WaitKnowledge.Lookup("LAZYWRITER_SLEEP").Title);
}
[Fact]
public void Samples_are_summed_by_wait_type_database_and_statement_without_background_waits()
{
var requests = new[]
{
new WaitingRequest(51, "LCK_M_S", 2000, "AX", "0xAA", "SELECT * FROM INVENTTRANS", 60),
new WaitingRequest(52, "lck_m_s", 500, "AX", "0xAA", "SELECT * FROM INVENTTRANS", 60),
new WaitingRequest(53, "PAGEIOLATCH_SH", 12, "AX", "0xBB", null, 0),
new WaitingRequest(54, "SLEEP_TASK", 1000, null, null, null, 0),
};
var snapshot = WaitSampling.Aggregate(requests, Now);
Assert.Equal(2, snapshot.Rows.Count);
var locks = snapshot.Rows[0];
Assert.Equal(("LCK_M_S", 2, 2500L, 2000L, 2), (locks.WaitType, locks.Sessions, locks.WaitTimeMs, locks.MaxWaitTimeMs, locks.BlockedSessions));
Assert.Equal(2, snapshot.Statements.Count);
Assert.Equal("SELECT * FROM INVENTTRANS", snapshot.Statements.Single(s => s.QueryKey == "0xAA").Text);
Assert.True(WaitSampling.IsLockWait("LCK_M_IX"));
}
}