Fix aggregation: proper DATE_FORMAT, escaped %

This commit is contained in:
mirivlad 2026-02-15 10:05:25 +00:00
parent 606ae60db8
commit 3575e1843e
1 changed files with 24 additions and 10 deletions

View File

@ -48,12 +48,20 @@ class ServerDetailController extends Model
// Запрос с агрегацией если нужно // Запрос с агрегацией если нужно
if ($groupBy) { if ($groupBy) {
// Используем агрегацию на основе aggregate_minutes
$bucketFormat = match(true) {
// Экранируем % для DATE_FORMAT
$aggConfig['aggregate_minutes'] >= 60 => '%Y-%m-%d %H:00', // 1 hour+
$aggConfig['aggregate_minutes'] >= 15 => '%Y-%m-%d %H:%i', // 15-59 min
default => '%Y-%m-%d %H:%i:00' // 1-14 min
};
$sql = " $sql = "
SELECT SELECT
AVG(sm.value) as value, AVG(sm.value) as value,
mn.name, mn.name,
mn.unit, mn.unit,
DATE_FORMAT(sm.created_at, '%Y-%m-%d %H:%i:00') as time_bucket DATE_FORMAT(sm.created_at, '{$bucketFormat}') as time_bucket
FROM server_metrics sm FROM server_metrics sm
JOIN metric_names mn ON sm.metric_name_id = mn.id JOIN metric_names mn ON sm.metric_name_id = mn.id
WHERE sm.server_id = :id WHERE sm.server_id = :id
@ -144,21 +152,27 @@ class ServerDetailController extends Model
private function getAggregationConfig(string $period, ?string $zoom): array private function getAggregationConfig(string $period, ?string $zoom): array
{ {
// Target: ~200-400 points on chart regardless of period
if ($zoom) { if ($zoom) {
return match($zoom) { return match($zoom) {
'1h' => ['interval' => 'INTERVAL 1 HOUR', 'groupBy' => null], // Short periods - show all points
'6h' => ['interval' => 'INTERVAL 6 HOUR', 'groupBy' => null], '1h' => ['interval' => 'INTERVAL 1 HOUR', 'groupBy' => null, 'aggregate_minutes' => 0],
'24h' => ['interval' => 'INTERVAL 24 HOUR', 'groupBy' => null], '6h' => ['interval' => 'INTERVAL 6 HOUR', 'groupBy' => null, 'aggregate_minutes' => 0],
'7d' => ['interval' => 'INTERVAL 7 DAY', 'groupBy' => "GROUP BY mn.id, time_bucket"], // Medium period - light aggregation
'30d' => ['interval' => 'INTERVAL 30 DAY', 'groupBy' => "GROUP BY mn.id, time_bucket"], '24h' => ['interval' => 'INTERVAL 24 HOUR', 'groupBy' => "GROUP BY mn.id, DATE_FORMAT(sm.created_at, '%Y-%m-%d %H:%i')", 'aggregate_minutes' => 1],
default => ['interval' => 'INTERVAL 24 HOUR', 'groupBy' => null] // Long periods - strong aggregation
'7d' => ['interval' => 'INTERVAL 7 DAY', 'groupBy' => "GROUP BY mn.id, DATE_FORMAT(sm.created_at, '%Y-%m-%d %H:%i')", 'aggregate_minutes' => 15],
'30d' => ['interval' => 'INTERVAL 30 DAY', 'groupBy' => "GROUP BY mn.id, DATE_FORMAT(sm.created_at, '%Y-%m-%d %H:00')", 'aggregate_minutes' => 60],
default => ['interval' => 'INTERVAL 24 HOUR', 'groupBy' => null, 'aggregate_minutes' => 0]
}; };
} }
// Default: base period aggregation
return match($period) { return match($period) {
'7d' => ['interval' => 'INTERVAL 7 DAY', 'groupBy' => "GROUP BY mn.id, time_bucket"], '7d' => ['interval' => 'INTERVAL 7 DAY', 'groupBy' => "GROUP BY mn.id, DATE_FORMAT(sm.created_at, '%Y-%m-%d %H:%i')", 'aggregate_minutes' => 15],
'30d' => ['interval' => 'INTERVAL 30 DAY', 'groupBy' => "GROUP BY mn.id, time_bucket"], '30d' => ['interval' => 'INTERVAL 30 DAY', 'groupBy' => "GROUP BY mn.id, DATE_FORMAT(sm.created_at, '%Y-%m-%d %H:00')", 'aggregate_minutes' => 60],
default => ['interval' => 'INTERVAL 24 HOUR', 'groupBy' => null] default => ['interval' => 'INTERVAL 24 HOUR', 'groupBy' => null, 'aggregate_minutes' => 0]
}; };
} }