refactor: optimize statistics retrieval by introducing a method to fetch current and previous records in a single query, reducing database load and improving performance

This commit is contained in:
2025-12-03 16:16:57 -05:00
parent f56ffbd936
commit 1d185d28db

View File

@@ -1303,28 +1303,33 @@ class Statistics extends Component
public function getHistoricalComparisonProperty()
{
try {
// Get current period statistics
$currentStats = $this->getStatisticsForPeriod($this->currentPeriod, $this->currentCustomDate);
// Get current period statistics with its previous record (for rate calculation)
$currentStats = $this->getStatisticsForPeriodWithPrevious($this->currentPeriod, $this->currentCustomDate);
// Get historical period statistics
$historicalStats = $this->getStatisticsForPeriod($this->historicalPeriod, $this->historicalCustomDate);
// Get historical period statistics with its previous record
$historicalStats = $this->getStatisticsForPeriodWithPrevious($this->historicalPeriod, $this->historicalCustomDate);
if (!$currentStats || !$historicalStats) {
if (!$currentStats || !$historicalStats || !$currentStats['stat'] || !$historicalStats['stat']) {
return null;
}
$current = $currentStats['stat'];
$historical = $historicalStats['stat'];
$currentPrevious = $currentStats['previous'];
$historicalPrevious = $historicalStats['previous'];
// Calculate differences and percentages
$comparison = [
'current' => $currentStats,
'historical' => $historicalStats,
'current' => $current,
'historical' => $historical,
'differences' => [
'cpu' => $this->calculateDifference($currentStats->cpuused, $currentStats->cpumax, $historicalStats->cpuused, $historicalStats->cpumax),
'memory' => $this->calculateDifference($currentStats->memoryused, $currentStats->memorymax, $historicalStats->memoryused, $historicalStats->memorymax),
'disk' => $this->calculateDifference($currentStats->diskused ?? 0, $currentStats->diskmax ?? 0, $historicalStats->diskused ?? 0, $historicalStats->diskmax ?? 0),
'network_in' => $this->calculateRateDifference($currentStats, $historicalStats, 'netin'),
'network_out' => $this->calculateRateDifference($currentStats, $historicalStats, 'netout'),
'disk_read' => $this->calculateRateDifference($currentStats, $historicalStats, 'diskread'),
'disk_write' => $this->calculateRateDifference($currentStats, $historicalStats, 'diskwrite'),
'cpu' => $this->calculateDifference($current->cpuused, $current->cpumax, $historical->cpuused, $historical->cpumax),
'memory' => $this->calculateDifference($current->memoryused, $current->memorymax, $historical->memoryused, $historical->memorymax),
'disk' => $this->calculateDifference($current->diskused ?? 0, $current->diskmax ?? 0, $historical->diskused ?? 0, $historical->diskmax ?? 0),
'network_in' => $this->calculateRateDifferenceOptimized($current, $historical, $currentPrevious, $historicalPrevious, 'netin'),
'network_out' => $this->calculateRateDifferenceOptimized($current, $historical, $currentPrevious, $historicalPrevious, 'netout'),
'disk_read' => $this->calculateRateDifferenceOptimized($current, $historical, $currentPrevious, $historicalPrevious, 'diskread'),
'disk_write' => $this->calculateRateDifferenceOptimized($current, $historical, $currentPrevious, $historicalPrevious, 'diskwrite'),
],
];
@@ -1335,6 +1340,30 @@ class Statistics extends Component
}
}
/**
* Get statistics for a period along with the previous record (for rate calculation)
* This reduces queries from 10+ to just 4 total
*/
protected function getStatisticsForPeriodWithPrevious(string $period, ?string $customDate = null): ?array
{
$stat = $this->getStatisticsForPeriod($period, $customDate);
if (!$stat) {
return null;
}
// Get the previous record for rate calculation
$previous = ServerStatistics::where('server_id', $this->server->id)
->where('DateTime', '<', $stat->DateTime)
->orderBy('DateTime', 'desc')
->first();
return [
'stat' => $stat,
'previous' => $previous,
];
}
protected function getStatisticsForPeriod(string $period, ?string $customDate = null)
{
$now = now();
@@ -1385,13 +1414,32 @@ class Statistics extends Component
if ($targetTime) {
// Find the statistic closest to the target time (within 30 minutes)
return ServerStatistics::where('server_id', $this->server->id)
->whereBetween('DateTime', [
$targetTime->copy()->subMinutes(30),
$targetTime->copy()->addMinutes(30)
])
->orderByRaw('ABS(TIMESTAMPDIFF(MINUTE, DateTime, ?))', [$targetTime])
->first();
// Use database-agnostic approach
$minTime = $targetTime->copy()->subMinutes(30);
$maxTime = $targetTime->copy()->addMinutes(30);
$stats = ServerStatistics::where('server_id', $this->server->id)
->whereBetween('DateTime', [$minTime, $maxTime])
->orderBy('DateTime', 'asc')
->get();
if ($stats->isEmpty()) {
return null;
}
// Find the closest one to target time (database-agnostic)
$closest = null;
$smallestDiff = PHP_INT_MAX;
foreach ($stats as $stat) {
$diff = abs($stat->DateTime->diffInSeconds($targetTime));
if ($diff < $smallestDiff) {
$smallestDiff = $diff;
$closest = $stat;
}
}
return $closest;
}
return null;
@@ -1417,23 +1465,16 @@ class Statistics extends Component
];
}
protected function calculateRateDifference($currentStat, $historicalStat, $field)
/**
* Calculate rate difference using pre-fetched previous stats (optimized)
* This eliminates N+1 queries - previous stats are fetched once per period
*/
protected function calculateRateDifferenceOptimized($currentStat, $historicalStat, $currentPrevious, $historicalPrevious, $field)
{
// Get previous stats to calculate rates
$currentPrevious = ServerStatistics::where('server_id', $this->server->id)
->where('DateTime', '<', $currentStat->DateTime)
->orderBy('DateTime', 'desc')
->first();
$historicalPrevious = ServerStatistics::where('server_id', $this->server->id)
->where('DateTime', '<', $historicalStat->DateTime)
->orderBy('DateTime', 'desc')
->first();
$currentRate = 0;
$historicalRate = 0;
if ($currentPrevious) {
if ($currentPrevious && $currentStat) {
$timeDiff = $currentStat->DateTime->diffInSeconds($currentPrevious->DateTime);
if ($timeDiff > 0) {
$currentDiff = max(0, ($currentStat->$field ?? 0) - ($currentPrevious->$field ?? 0));
@@ -1441,7 +1482,7 @@ class Statistics extends Component
}
}
if ($historicalPrevious) {
if ($historicalPrevious && $historicalStat) {
$timeDiff = $historicalStat->DateTime->diffInSeconds($historicalPrevious->DateTime);
if ($timeDiff > 0) {
$historicalDiff = max(0, ($historicalStat->$field ?? 0) - ($historicalPrevious->$field ?? 0));
@@ -1460,6 +1501,25 @@ class Statistics extends Component
];
}
/**
* @deprecated Use calculateRateDifferenceOptimized instead
*/
protected function calculateRateDifference($currentStat, $historicalStat, $field)
{
// Get previous stats to calculate rates
$currentPrevious = ServerStatistics::where('server_id', $this->server->id)
->where('DateTime', '<', $currentStat->DateTime)
->orderBy('DateTime', 'desc')
->first();
$historicalPrevious = ServerStatistics::where('server_id', $this->server->id)
->where('DateTime', '<', $historicalStat->DateTime)
->orderBy('DateTime', 'desc')
->first();
return $this->calculateRateDifferenceOptimized($currentStat, $historicalStat, $currentPrevious, $historicalPrevious, $field);
}
public function getHistoricalComparisonExportDataProperty()
{
$comparison = $this->historicalComparison;