@page "/instanser/{Name}"
@inject InsightRepository Repository
@inject Display Display
@if (_instance is null)
{
Ukendt instans · SQLInsight Pro
Ukendt instans
Der findes ingen instans med navnet @Name.
return;
}
@_instance.Name · SQLInsight Pro
Instanser / @_instance.Name
@_instance.Name
@_instance.ServerName · @Display.Release(_instance.ProductVersion, _instance.EngineEdition) (@_instance.ProductVersion @_instance.ProductLevel @_instance.ProductUpdateLevel) · @_instance.Edition
· sidst set @Display.Ago(_instance.LastSeenAt)
@if (_instance.IsFailing)
{
Seneste forsøg på at nå instansen fejlede (@Display.Time(_instance.LastErrorAt)):
@_instance.LastError
}
@if (_instance.UsedLegacyFallback)
{
Forbindelsen bruger legacy ODBC-laget, fordi instansen er for gammel til SqlClient. Krypteringen kan være svagere.
}
Aktive fund
@_findings.Count fund
Største ventetider, seneste 24 timer
uden harmløse baggrundsventetider
@if (_waits.Count == 0)
{
Endnu ikke nok målinger (ventetider kræver to målinger).
}
else
{
var total = Math.Max(1, _waits.Sum(w => w.WaitTimeMs));
| Wait type | Kategori | Ventetid | Andel | Gns. pr. wait | Signal |
@foreach (var w in _waits)
{
| @w.WaitType |
@w.Category |
@Display.Number(w.WaitTimeMs / 1000.0, 1) s |
@Display.Number(100.0 * w.WaitTimeMs / total) % |
@Display.Number(w.WaitingTasks == 0 ? 0 : (double)w.WaitTimeMs / w.WaitingTasks, 1) ms |
@Display.Number(w.WaitTimeMs == 0 ? 0 : 100.0 * w.SignalWaitTimeMs / w.WaitTimeMs) % |
}
}
Diskhastighed pr. drev, seneste 24 timer
@if (_diskSeries.Count > 0)
{
@foreach (var s in _diskSeries.Take(6))
{
}
}
I/O-latens pr. fil, seneste 24 timer
@if (_files.Count == 0)
{
Endnu ikke nok målinger.
}
else
{
| Database | Fil | Type | Læsninger | Gns. læs | Skrivninger | Gns. skriv |
@foreach (var f in _files.Take(25))
{
| @f.DatabaseName |
@f.FileId |
@f.FileType |
@Display.Number(f.Reads) |
@Ms(f.AverageReadMs) |
@Display.Number(f.Writes) |
@Ms(f.AverageWriteMs) |
}
}
Blocking, seneste 24 timer
@if (_blocking.Count == 0)
{
Ingen blocking over 5 sekunder.
}
else
{
| Tidspunkt | Head blocker | Blokerede | Længste |
@foreach (var b in _blocking.Take(20))
{
var head = b.Sessions.FirstOrDefault();
| @Display.Time(b.SampledAt) |
@b.HeadSessionId @head?.Status @head?.ProgramName |
@b.BlockedCount |
@Display.Number(b.MaxWaitMs / 1000.0) s |
}
}
Deadlocks, seneste 7 dage
@if (_deadlocks.Count == 0)
{
Ingen deadlocks registreret.
}
else
{
| Tidspunkt | Offer | Graf |
@foreach (var d in _deadlocks.Take(20))
{
var victim = d.Processes.FirstOrDefault(p => p.IsVictim);
| @Display.Time(d.OccurredAt) |
session @victim?.SessionId @victim?.ClientApp |
.xdl |
}
}
Ikke målbart på denne instans
@if (_notMeasurable.Count == 0)
{
Alle regler, der er relevante for instansen, kunne evalueres.
}
else
{
Disse regler kunne ikke vurderes. Det er ikke det samme som "OK".
| Regel | | Årsag |
@foreach (var r in _notMeasurable)
{
| @r.RuleId | @r.RuleTitle | @r.Reason |
}
}
@if (_notApplicable.Count > 0)
{
Ikke relevant for @Display.Release(_instance.ProductVersion, _instance.EngineEdition) (@_notApplicable.Count)
Regler om noget, denne SQL Server-version ikke har (fx Query Store eller system_health). Det er ikke et hul i overvågningen.
| Regel | | Hvorfor |
@foreach (var r in _notApplicable)
{
| @r.RuleId | @r.RuleTitle | @r.Reason |
}
}
Løst de seneste 30 dage
@if (_resolved.Count == 0)
{
Ingen.
}
else
{
| Fund | Aktivt fra | Løst |
@foreach (var f in _resolved)
{
| @f.Title | @Display.Time(f.FirstSeenAt) | @Display.Time(f.ResolvedAt) |
}
}
@code {
[Parameter] public string Name { get; set; } = string.Empty;
private InstanceOverview? _instance;
private IReadOnlyList _findings = [];
private IReadOnlyList _resolved = [];
private IReadOnlyList _notMeasurable = [];
private IReadOnlyList _notApplicable = [];
private IReadOnlyList _cpuSql = [], _cpuOther = [], _batches = [], _ple = [];
private IReadOnlyList _waits = [];
private IReadOnlyList _files = [];
private IReadOnlyList _disks = [];
private IReadOnlyList _diskSeries = [];
private IReadOnlyList _blocking = [];
private IReadOnlyList _deadlocks = [];
protected override async Task OnInitializedAsync()
{
_instance = await Repository.GetInstanceAsync(Name);
if (_instance is null)
{
return;
}
var id = _instance.InstanceId;
var day = DateTimeOffset.UtcNow.AddDays(-1);
_findings = await Repository.GetActiveFindingsAsync(id);
_resolved = await Repository.GetRecentlyResolvedAsync(id, 30);
var states = await Repository.GetRuleStatesAsync(id);
_notMeasurable = states.Where(r => r.Outcome is RuleOutcome.NotMeasurable or RuleOutcome.Error).ToList();
_notApplicable = states.Where(r => r.Outcome == RuleOutcome.NotApplicable).ToList();
_cpuSql = await Repository.GetMetricAsync(id, Metrics.CpuSqlServer, day);
_cpuOther = await Repository.GetMetricAsync(id, Metrics.CpuOther, day);
_batches = await Repository.GetMetricAsync(id, Metrics.BatchRequestsPerSecond, day);
_ple = await Repository.GetMetricAsync(id, Metrics.PageLifeExpectancy, day);
_waits = await Repository.GetTopWaitsAsync(id, day, 12);
_files = await Repository.GetFileLatencyAsync(id, day);
_disks = (await Repository.GetDiskActivityAsync(id, day, DateTimeOffset.UtcNow)).Select(d => new SQLInsight.Reports.DiskComparison(d, null)).ToList();
_diskSeries = await Repository.GetDiskSeriesAsync(id, day);
_blocking = await Repository.GetBlockingAsync(id, day);
_deadlocks = await Repository.GetDeadlocksAsync(id, DateTimeOffset.UtcNow.AddDays(-7));
}
private static string Ms(double? value) => value is { } v ? $"{Display.Number(v, 1)} ms" : "–";
/// The time window analysis: the last hour, or half an hour on each side of an event.
private string AnalysisUrl(DateTime? around)
{
var url = "/instanser/" + Uri.EscapeDataString(_instance!.Name) + "/analyse";
if (around is not { } at)
{
return url;
}
var (from, to) = SQLInsight.Reports.TimeWindow.Around(at);
return url + "?fra=" + Uri.EscapeDataString(SQLInsight.Reports.TimeWindow.ToInput(from, Display.Zone))
+ "&til=" + Uri.EscapeDataString(SQLInsight.Reports.TimeWindow.ToInput(to, Display.Zone));
}
private static string LatencyClass(double? value, double threshold) => value >= threshold ? "bad" : string.Empty;
}