Inizio gestione calcolo spazio DB

This commit is contained in:
Samuele Locatelli
2025-07-04 10:54:30 +02:00
parent 4f841a09ad
commit 0829144478
18 changed files with 345 additions and 5 deletions
+83
View File
@@ -31,6 +31,89 @@ namespace MP.Data.Controllers
#region Public Methods
/// <summary>
/// Restituisce info dimensione, tabelle e num righe DB gestiti
/// </summary>
/// <returns></returns>
public List<DbSizeModel> AllDbInfo()
{
List<DbSizeModel> dbResult = new List<DbSizeModel>();
string stp_DbInfo = @"
;WITH TableRowCounts AS (
SELECT
t.name AS TableName,
SUM(p.rows) AS RowNum
FROM sys.tables t
JOIN sys.partitions p ON t.object_id = p.object_id
WHERE p.index_id IN (0, 1) -- heap or clustered index
GROUP BY t.name
),
LargestTable AS (
SELECT TOP 1 RowNum, TableName
FROM TableRowCounts
ORDER BY RowNum DESC
)
SELECT
DB_name() as DbName,
CAST(SUM(size) * 8.0 / 1024 AS DECIMAL(18,2)) AS DbSizeMb,
(SELECT COUNT(*) FROM sys.tables) AS NumTables,
(SELECT TableName FROM LargestTable) AS BigTable,
(SELECT RowNum FROM LargestTable) AS BigTableRows
FROM sys.master_files
WHERE database_id = DB_ID();
";
// leggo per DB principale
if (!string.IsNullOrEmpty(_configuration.GetConnectionString("MP.All")))
{
using (var dbCtx = new MoonProContext(_configuration))
{
var singleRes = dbCtx
.DbSetDbSize
.FromSqlRaw(stp_DbInfo)
.AsEnumerable()
.FirstOrDefault();
if (singleRes != null)
{
dbResult.Add(singleRes);
}
}
}
// leggo per FluxLog
if (!string.IsNullOrEmpty(_configuration.GetConnectionString("MP.FluxLog")))
{
using (var dbCtx = new MoonPro_FluxContext(_configuration))
{
var singleRes = dbCtx
.DbSetDbSize
.FromSqlRaw(stp_DbInfo)
.AsEnumerable()
.FirstOrDefault();
if (singleRes != null)
{
dbResult.Add(singleRes);
}
}
}
// leggo per Stats
if (!string.IsNullOrEmpty(_configuration.GetConnectionString("MP.Stats")))
{
using (var dbCtx = new MoonPro_STATSContext(_configuration))
{
var singleRes = dbCtx
.DbSetDbSize
.FromSqlRaw(stp_DbInfo)
.AsEnumerable()
.FirstOrDefault();
if (singleRes != null)
{
dbResult.Add(singleRes);
}
}
}
return dbResult;
}
/// <summary>
/// Elenco da tabella Config
/// </summary>
+1
View File
@@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Data;
using System.Drawing.Drawing2D;
using System.Linq;
using ZXing;
using static MP.Core.Objects.Enums;
namespace MP.Data.Controllers
+14
View File
@@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
namespace MP.Data.DbModels
{
public class DbSizeModel
{
[Key]
public string DbName { get; set; } = "";
public decimal DbSizeMb { get; set; } = 0;
public int NumTables { get; set; } = 0;
public string BigTable { get; set; } = "";
public long BigTableRows { get; set; } = 0;
}
}
+1
View File
@@ -38,6 +38,7 @@ namespace MP.Data
#region Public Properties
public virtual DbSet<DbSizeModel> DbSetDbSize { get; set; }
public virtual DbSet<AlarmLogModel> DbSetAlarmLog { get; set; }
public virtual DbSet<AnagKeyValueModel> DbSetAKV { get; set; }
public virtual DbSet<AnagEventiModel> DbSetAnagEventi { get; set; }
+1
View File
@@ -48,6 +48,7 @@ namespace MP.Data
#region Public Properties
public virtual DbSet<DbSizeModel> DbSetDbSize { get; set; }
public virtual DbSet<AnagArticoliModel> DbSetArticoli { get; set; }
public virtual DbSet<MacchineModel> DbSetMacchine { get; set; }
public virtual DbSet<FluxLogModel> DbSetFluxLog { get; set; }
+1
View File
@@ -36,6 +36,7 @@ namespace MP.Data
#region Public Properties
public virtual DbSet<DbSizeModel> DbSetDbSize { get; set; }
public virtual DbSet<AnagFLTransModel> DbSetAnagFLTrans { get; set; }
public virtual DbSet<StatsAnagArticoli> DbSetArticoli { get; set; }
public virtual DbSet<AzioniUL> DbSetAzioniUL { get; set; }
+35
View File
@@ -47,6 +47,41 @@ namespace MP.Data.Services
#region Public Methods
/// <summary>
/// Restituisce info dimensione, tabelle e num righe DB
/// </summary>
/// <returns></returns>
public List<DbSizeModel> AllDbInfo()
{
// setup parametri costanti
string source = "DB";
Stopwatch sw = new Stopwatch();
sw.Start();
List<DbSizeModel> result = new List<DbSizeModel>();
// cerco in redis...
string currKey = $"{redisBaseKey}:DbInfo:ALL";
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<DbSizeModel>>($"{rawData}");
source = "REDIS";
}
else
{
result = dbController.AllDbInfo();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, UltraFastCache);
}
if (result == null)
{
result = new List<DbSizeModel>();
}
sw.Stop();
Log.Debug($"AllDbInfo | {source} | {sw.Elapsed.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Elenco INFO IOB da tab Macchine gestite + RemoteRebootLog
/// </summary>
+38
View File
@@ -0,0 +1,38 @@
<div class="card shadow">
<div class="card-header bg-success bg-opacity-50 bg-gradient">
<div class="fs-5 fw-bold">Current DB Info</div>
</div>
<div class="card-body">
@if (ListRecord == null || ListRecord.Count == 0)
{
<div class="alert alert-info fs-5">Nessun record disponibile</div>
}
else
{
<table class="table table-sm table-striped">
<thead>
<tr>
<th><i class="fa-solid fa-database"></i> DB <Sorter ParamName="DbName" IsAsc="@sortAsc" CurrParam="@sortField" sortReq="SortRequested"></Sorter></th>
<th class="text-end"><Sorter ParamName="DbSizeMb" IsAsc="@sortAsc" CurrParam="@sortField" sortReq="SortRequested"></Sorter> <i class="fa-solid fa-memory"></i> Size (Mb)</th>
<th class="text-end"><Sorter ParamName="NumTable" IsAsc="@sortAsc" CurrParam="@sortField" sortReq="SortRequested"></Sorter> Num Tab</th>
<th class="text-end"><Sorter ParamName="BigTable" IsAsc="@sortAsc" CurrParam="@sortField" sortReq="SortRequested"></Sorter> Biggest Tab</th>
<th class="text-end"><Sorter ParamName="BigTableRows" IsAsc="@sortAsc" CurrParam="@sortField" sortReq="SortRequested"></Sorter> Num Rows</th>
</tr>
</thead>
<tbody>
@foreach (var item in ListRecord)
{
<tr>
<td>@item.DbName</td>
<td class="text-end">@item.DbSizeMb.ToString("N2")</td>
<td class="text-end">@item.NumTables</td>
<td class="text-end">@item.BigTable</td>
<td class="text-end">@item.BigTableRows.ToString("N0")</td>
</tr>
}
</tbody>
</table>
}
</div>
</div>
+127
View File
@@ -0,0 +1,127 @@
using EgwCoreLib.Razor;
using Microsoft.AspNetCore.Components;
using MP.Data.DbModels;
using MP.Data.Services;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MP.Land.Components
{
public partial class DbInfoMan
{
#region Protected Properties
[Inject]
protected LandDataService LDService { get; set; }
protected List<DbSizeModel> ListRecord { get; set; } = new List<DbSizeModel>();
#endregion Protected Properties
#region Protected Methods
protected override void OnParametersSet()
{
ReloadData();
}
protected void SortRequested(Sorter.SortCallBack e)
{
if (sortField == e.ParamName)
{
sortAsc = e.IsAscending;
}
sortField = e.ParamName;
RefreshDisplay();
}
#endregion Protected Methods
#region Private Fields
private bool sortAsc = true;
private string sortField = "";
#endregion Private Fields
#region Private Methods
private void RefreshDisplay()
{
// se ho ordinamento riordino...
if (!string.IsNullOrEmpty(sortField))
{
switch (sortField)
{
case "DbName":
if (sortAsc)
{
ListRecord = ListRecord.OrderBy(x => x.DbName).ToList();
}
else
{
ListRecord = ListRecord.OrderByDescending(x => x.DbName).ToList();
}
break;
case "DbSizeMb":
if (sortAsc)
{
ListRecord = ListRecord.OrderBy(x => x.DbSizeMb).ToList();
}
else
{
ListRecord = ListRecord.OrderByDescending(x => x.DbSizeMb).ToList();
}
break;
case "NumTable":
if (sortAsc)
{
ListRecord = ListRecord.OrderBy(x => x.NumTables).ToList();
}
else
{
ListRecord = ListRecord.OrderByDescending(x => x.NumTables).ToList();
}
break;
case "BigTable":
if (sortAsc)
{
ListRecord = ListRecord.OrderBy(x => x.BigTable).ToList();
}
else
{
ListRecord = ListRecord.OrderByDescending(x => x.BigTable).ToList();
}
break;
case "BigTableRows":
if (sortAsc)
{
ListRecord = ListRecord.OrderBy(x => x.BigTableRows).ToList();
}
else
{
ListRecord = ListRecord.OrderByDescending(x => x.BigTableRows).ToList();
}
break;
default:
ListRecord = ListRecord.OrderBy(x => x.DbName).ToList();
break;
}
}
}
private void ReloadData()
{
ListRecord = LDService.AllDbInfo();
}
#endregion Private Methods
}
}
+1 -1
View File
@@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>MP.Land</RootNamespace>
<Version>6.16.2507.0315</Version>
<Version>6.16.2507.0410</Version>
<Configurations>Debug;Release;Debug_LiManDebug</Configurations>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<RunAnalyzersDuringBuild>True</RunAnalyzersDuringBuild>
+3
View File
@@ -0,0 +1,3 @@
@page "/DbInfo"
<DbInfoMan></DbInfoMan>
+25
View File
@@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Components;
namespace MP.Land.Pages
{
public partial class DbInfo : ComponentBase
{
#region Protected Properties
[Inject]
protected Data.LMessageService MServ { get; set; } = null!;
#endregion Protected Properties
#region Protected Methods
protected override void OnInitialized()
{
MServ.ShowSearch = true;
MServ.PageName = "DB Info";
MServ.PageIcon = "fas fa-database";
}
#endregion Protected Methods
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>Modulo Tablet MAPO - DotNet6</i>
<h4>Versione: 6.16.2507.0315</h4>
<h4>Versione: 6.16.2507.0410</h4>
<br />
Note di rilascio:
<ul>
+1 -1
View File
@@ -1 +1 @@
6.16.2507.0315
6.16.2507.0410
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>6.16.2507.0315</version>
<version>6.16.2507.0410</version>
<url>https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/MP.Land.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
+9
View File
@@ -99,6 +99,15 @@
</div>
@if (IsSuperAdmin)
{
<div class="nav-item px-2">
<NavLink class="nav-link py-0 px-2 mb-0" href="DbInfo">
<span class="fas fa-database fs-4 pe-2" aria-hidden="true"></span>
@if (showText)
{
<span class="@hideText">DBs Info</span>
}
</NavLink>
</div>
<div class="nav-item px-2">
<NavLink class="nav-link py-0 px-2 mb-0" href="TaskScheduler">
<span class="fas fa-stopwatch fs-4 pe-2" aria-hidden="true"></span>
+2
View File
@@ -58,9 +58,11 @@
"ConnectionStrings": {
"DefaultConnection": "Server=SQL2016DEV;Database=MoonPro;Trusted_Connection=True;MultipleActiveResultSets=true",
"MP.All": "Server=SQL2016DEV;Database=MoonPro;User ID=sa;Password=keyhammer16;integrated security=False;MultipleActiveResultSets=True;App=MP.Land;",
"MP.FluxLog": "Server=SQL2016DEV;Database=MoonPro_FluxData;User ID=sa;Password=keyhammer16;integrated security=False;MultipleActiveResultSets=True;App=MP.Land;",
"MP.Land": "Server=SQL2016DEV;Database=MoonPro;User ID=sa;Password=keyhammer16;integrated security=False;MultipleActiveResultSets=True;App=MP.Land;",
"MP.Land.Auth": "Server=SQL2016DEV;Database=MoonPro_Anagrafica;User ID=sa;Password=keyhammer16;integrated security=False;MultipleActiveResultSets=True;App=MP.Land;",
"MP.Tab": "Server=SQL2016DEV;Database=MoonPro; User ID=sa;Password=keyhammer16; integrated security=False; MultipleActiveResultSets=True; App=MP.Land;",
"MP.Stats": "Server=SQL2016DEV;Database=MoonPro_STATS; User ID=sa;Password=keyhammer16; integrated security=False; MultipleActiveResultSets=True; App=MP.Land;",
//"Redis": "redis.ufficio:26379, serviceName=devel, defaultDatabase=1, keepAlive=180, connectTimeout=5000, syncTimeout=5000, asyncTimeout=5000, abortConnect=false, ssl=false, allowAdmin=true",
"Redis": "redis.ufficio:26379, serviceName=devel, DefaultDatabase=5, keepAlive=180, connectTimeout=15000, syncTimeout=15000, asyncTimeout=15000, abortConnect=false, ssl=false, allowAdmin=true"
},
+1 -1
View File
@@ -48,7 +48,7 @@
}
else if (SearchRecords.Count==0)
{
<div class="alert alert-info fs-5">Nessun record trovato dati i criteri espressi</div>
<div class="alert alert-info fs-5">Nessun record trovato</div>
}
else
{