MetricAssessment rates CPU (SQL/other), batch requests, compilations (against batches), page life expectancy (300 s per 4 GB buffer pool, average and dips over 50 %, max server memory unset), user connections, memory grants pending, processes blocked and disk latency as OK, Bemærk or Reagér with a concrete next step and link, plus a plain Danish "Hvad betyder det?" for each. Shown under every graph on the instance page (now all eight metrics) and in the analysis, per drive in the disk table, and in the analysis PDF. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
51 lines
3 KiB
Text
51 lines
3 KiB
Text
@* Disk speed per drive: IOPS, MB/s and average latency, optionally against the normal for the same hours. *@
|
||
@if (Disks.Count == 0)
|
||
{
|
||
<p class="muted">@Empty</p>
|
||
}
|
||
else
|
||
{
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Drev</th><th class="num">Filer</th><th class="num">Læs IOPS</th><th class="num">Skriv IOPS</th>
|
||
<th class="num">Læs MB/s</th><th class="num">Skriv MB/s</th><th class="num">Gns. læs</th><th class="num">Gns. skriv</th><th>Vurdering</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@foreach (var d in Disks)
|
||
{
|
||
var w = d.Window;
|
||
<tr>
|
||
<td class="mono">@w.Volume</td>
|
||
<td class="num">@Files(w)</td>
|
||
<td class="num">@Display.Number(w.ReadIops ?? 0, 1)</td>
|
||
<td class="num">@Display.Number(w.WriteIops ?? 0, 1)</td>
|
||
<td class="num">@Display.Number(w.ReadMbPerSecond ?? 0, 1)</td>
|
||
<td class="num">@Display.Number(w.WriteMbPerSecond ?? 0, 1)</td>
|
||
<td class="num @(w.AverageReadMs >= 20 || Worse(w.AverageReadMs, d.Normal?.AverageReadMs) ? "bad" : "")">@Ms(w.AverageReadMs)@Normal(d.Normal?.AverageReadMs)</td>
|
||
<td class="num @(w.AverageWriteMs >= (w.DataFiles == 0 && w.LogFiles > 0 ? 5 : 20) || Worse(w.AverageWriteMs, d.Normal?.AverageWriteMs) ? "bad" : "")">@Ms(w.AverageWriteMs)@Normal(d.Normal?.AverageWriteMs)</td>
|
||
<td><AssessmentNote Assessment="SQLInsight.Reports.MetricAssessment.AssessDisk(w)" InstanceName="@InstanceName" /></td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
<details><summary>Hvad betyder det?</summary><p>@SQLInsight.Reports.MetricAssessment.Explanation("disk.read")</p><p>@SQLInsight.Reports.MetricAssessment.Explanation("disk.write.log")</p><p>@SQLInsight.Reports.MetricAssessment.Explanation("disk.write")</p></details>
|
||
<p class="muted">Latens er gennemsnitstiden pr. læsning/skrivning set fra SQL Server (sys.dm_io_virtual_file_stats). Datafiler bør ligge under 10-20 ms, logfiler under 5 ms.@(ShowNormal ? " I parentes: det normale for samme klokkeslæt de foregående uger." : "")</p>
|
||
}
|
||
|
||
@code {
|
||
[Parameter, EditorRequired] public IReadOnlyList<SQLInsight.Reports.DiskComparison> Disks { get; set; } = [];
|
||
[Parameter] public string Empty { get; set; } = "Ingen målinger pr. drev endnu.";
|
||
[Parameter] public bool ShowNormal { get; set; }
|
||
[Parameter] public string? InstanceName { get; set; }
|
||
|
||
private static string Ms(double? value) => value is { } v ? $"{Display.Number(v, 1)} ms" : "–";
|
||
|
||
private string Normal(double? value) => ShowNormal && value is { } v ? $" ({Display.Number(v, 1)})" : "";
|
||
|
||
private static string Files(SQLInsight.Core.Data.DiskActivity d) =>
|
||
d.DataFiles + d.LogFiles == 0 ? "–" : $"{d.DataFiles} data · {d.LogFiles} log";
|
||
|
||
private static bool Worse(double? now, double? normal) => now is { } n && normal is > 0 and var m && n >= m * 2 && n - m >= 2;
|
||
}
|