Add LIMIT to prevent timeout on large date ranges

- Use subquery to limit raw data before aggregation
- Prevents loading millions of rows for 30d view
- Limit 5000 rows for non-aggregated queries
- Fixes 504 timeout errors
This commit is contained in:
mirivlad 2026-04-25 19:20:35 +08:00
parent 9b7e5afd4f
commit c07438d0cc
1 changed files with 16 additions and 10 deletions

View File

@ -122,19 +122,24 @@ class ServerDetailController extends Model
$endStr = $endDate->format('Y-m-d H:i:s'); $endStr = $endDate->format('Y-m-d H:i:s');
// Запрос с агрегацией если нужно // Запрос с агрегацией если нужно
// Используем подзапрос для ограничения данных и предотвращения таймаута
if ($groupBy) { if ($groupBy) {
$sql = " $sql = "
SELECT SELECT
AVG(sm.value) as value, AVG(inner_q.value) as value,
mn.name, inner_q.name,
mn.unit, inner_q.unit,
DATE_FORMAT(sm.created_at, '{$bucketFormat}') as time_bucket DATE_FORMAT(inner_q.created_at, '{$bucketFormat}') as time_bucket
FROM server_metrics sm FROM (
JOIN metric_names mn ON sm.metric_name_id = mn.id SELECT sm.value, mn.name, mn.unit, sm.created_at
WHERE sm.server_id = :id FROM server_metrics sm
AND sm.created_at >= :start_date JOIN metric_names mn ON sm.metric_name_id = mn.id
AND sm.created_at <= :end_date WHERE sm.server_id = :id
AND mn.name != 'uptime' AND sm.created_at >= :start_date
AND sm.created_at <= :end_date
AND mn.name != 'uptime'
ORDER BY sm.created_at ASC
) inner_q
{$groupBy} {$groupBy}
ORDER BY time_bucket ASC ORDER BY time_bucket ASC
"; ";
@ -150,6 +155,7 @@ class ServerDetailController extends Model
AND sm.created_at <= :end_date AND sm.created_at <= :end_date
AND mn.name != 'uptime' AND mn.name != 'uptime'
ORDER BY sm.created_at ASC ORDER BY sm.created_at ASC
LIMIT 5000
"; ";
$stmt = $this->pdo->prepare($sql); $stmt = $this->pdo->prepare($sql);
$stmt->execute([':id' => $id, ':start_date' => $startStr, ':end_date' => $endStr]); $stmt->execute([':id' => $id, ':start_date' => $startStr, ':end_date' => $endStr]);