diff --git a/extensions/Servers/Proxmox/Livewire/Statistics.php b/extensions/Servers/Proxmox/Livewire/Statistics.php index b103bf4bc..6b5255b2e 100644 --- a/extensions/Servers/Proxmox/Livewire/Statistics.php +++ b/extensions/Servers/Proxmox/Livewire/Statistics.php @@ -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;