perf(stats): 使用数据库端聚合优化统计查询

This commit is contained in:
ssss
2026-07-03 14:28:35 +08:00
parent d3e4b2b8de
commit f771abb6bf

View File

@@ -1,106 +1,120 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using WCTDataMiner.Core.Data;
using WCTDataMiner.Core.Models;
namespace WCTDataMiner.Core.Services;
/// <summary>
/// 统计查询服务
/// 统计查询服务 - 使用数据库端聚合优化内存效率
/// </summary>
public class StatsService
{
private readonly WctMinerDbContext _context;
private readonly ILogger<StatsService> _logger;
public StatsService(WctMinerDbContext context)
public StatsService(WctMinerDbContext context, ILogger<StatsService> logger)
{
_context = context;
_logger = logger;
}
/// <summary>
/// 获取整体统计摘要
/// 获取整体统计摘要(并行查询优化)
/// </summary>
public async Task<StatsSummary> GetSummaryAsync()
{
var scenarioCount = await _context.TestScenarios.CountAsync();
var qfodCount = await _context.QfodRecords.CountAsync();
var plossCount = await _context.PlossRecords.CountAsync();
var panelCount = await _context.TxPanels.CountAsync();
var hardwareCount = await _context.TxHardwares.CountAsync();
var softwareCount = await _context.TxSoftwares.CountAsync();
var rxTypeCount = await _context.RxTypes.CountAsync();
// 使用 Task.WhenAll 并行执行多个查询
var tasks = new[]
{
_context.TestScenarios.CountAsync(),
_context.QfodRecords.CountAsync(),
_context.PlossRecords.CountAsync(),
_context.TxPanels.CountAsync(),
_context.TxHardwares.CountAsync(),
_context.TxSoftwares.CountAsync(),
_context.RxTypes.CountAsync()
};
return new StatsSummary(
scenarioCount, qfodCount, plossCount,
panelCount, hardwareCount, softwareCount, rxTypeCount
var results = await Task.WhenAll(tasks);
var summary = new StatsSummary(
results[0], results[1], results[2],
results[3], results[4], results[5], results[6]
);
_logger.LogDebug("统计摘要: Scenarios={ScenarioCount}, Qfod={QfodCount}, Ploss={PlossCount}",
summary.ScenarioCount, summary.QfodCount, summary.PlossCount);
return summary;
}
/// <summary>
/// 按FOD类型统计Qfod记录
/// 按FOD类型统计Qfod记录(数据库端聚合)
/// </summary>
public async Task<List<FodTypeStats>> GetStatsByFodTypeAsync()
{
// 先加载到内存再分组EF Core 对 GroupBy + 自定义类型有限制)
var data = await _context.QfodRecords
.Select(r => r.FodType)
.ToListAsync();
return data
.GroupBy(f => f)
// 使用数据库端 GroupBy
var stats = await _context.QfodRecords
.GroupBy(r => r.FodType)
.Select(g => new FodTypeStats(g.Key, g.Count()))
.OrderBy(s => s.FodType)
.ToList();
.ToListAsync();
_logger.LogDebug("按 FOD 类型统计完成: {Count} 种类型", stats.Count);
return stats;
}
/// <summary>
/// 按面板类型统计
/// 按面板类型统计(数据库端聚合 - 使用维度表反向统计)
/// </summary>
public async Task<List<DimensionStats>> GetStatsByPanelAsync()
{
var data = await _context.TestScenarios
.Include(s => s.TxPanel)
.Select(s => s.TxPanel.Name)
// 方式: 使用维度表反向统计(更高效)
var stats = await _context.TxPanels
.Select(p => new DimensionStats(
p.Name,
p.TestScenarios.Count()
))
.OrderByDescending(s => s.Count)
.ToListAsync();
return data
.GroupBy(n => n)
.Select(g => new DimensionStats(g.Key, g.Count()))
.OrderByDescending(s => s.Count)
.ToList();
_logger.LogDebug("按面板类型统计完成: {Count} 种面板", stats.Count);
return stats;
}
/// <summary>
/// 按硬件版本统计
/// 按硬件版本统计(数据库端聚合)
/// </summary>
public async Task<List<DimensionStats>> GetStatsByHardwareAsync()
{
var data = await _context.TestScenarios
.Include(s => s.TxHardware)
.Select(s => s.TxHardware.Version)
var stats = await _context.TxHardwares
.Select(h => new DimensionStats(
h.Version,
h.TestScenarios.Count()
))
.OrderByDescending(s => s.Count)
.ToListAsync();
return data
.GroupBy(v => v)
.Select(g => new DimensionStats(g.Key, g.Count()))
.OrderByDescending(s => s.Count)
.ToList();
_logger.LogDebug("按硬件版本统计完成: {Count} 种版本", stats.Count);
return stats;
}
/// <summary>
/// 按RX类型统计
/// 按RX类型统计(数据库端聚合)
/// </summary>
public async Task<List<DimensionStats>> GetStatsByRxTypeAsync()
{
var data = await _context.TestScenarios
.Include(s => s.RxType)
.Select(s => s.RxType.Name)
var stats = await _context.RxTypes
.Select(r => new DimensionStats(
r.Name,
r.TestScenarios.Count()
))
.OrderByDescending(s => s.Count)
.ToListAsync();
return data
.GroupBy(n => n)
.Select(g => new DimensionStats(g.Key, g.Count()))
.OrderByDescending(s => s.Count)
.ToList();
_logger.LogDebug("按 RX 类型统计完成: {Count} 种类型", stats.Count);
return stats;
}
}