Bueno, acabo de hacer algunas pruebas… Y diría que el problema no es seguramente las consultas a DuckDB (creo que ya habíamos hecho este tipo de pruebas directamente en dev en Gladys ^^). Debe ser simplemente el renderizado o más bien la construcción de las series…:
- Agregación por intervalo temporal - Consulta TimeBucket
SELECT
device_feature_id,
TIME_BUCKET(INTERVAL 1752 MINUTES, created_at) AS created_at,
AVG(value) AS value,
MAX(value) AS max_value,
MIN(value) AS min_value,
SUM(value) AS sum_value,
COUNT(value) AS count_value
FROM t_device_feature_state
WHERE device_feature_id IN (
'eaa982b7-a3c8-4b4d-b2d0-5a5cf5245938',
'e9079170-4654-4fad-b726-23a36c793905',
'c59fca37-54f3-418b-b27c-857e08e2a0fb',
'da79df66-dcff-438e-859c-39b641fd15e9',
'5eba10ac-4c3a-479c-aba7-a1e74a00d914',
'4b5e90f0-a86b-405b-8ca1-953705ef79a3',
'c92f8fa3-d841-4692-bd3a-e5addb760a73',
'b5445f10-7aa9-41bf-8cae-d2f30498652f',
'08e90478-4bb2-4a08-986f-3d6f212c95f1',
'85311f8c-334f-4b7e-8294-2b841c0b8fe8'
)
AND created_at > TIMESTAMP '2024-12-14 10:04:11.478'
GROUP BY
device_feature_id,
created_at
ORDER BY
device_feature_id,
created_at;
- División por percentiles - Consulta NTILE(300)
WITH intervals AS (
SELECT
device_feature_id,
created_at,
value,
NTILE(300) OVER (
PARTITION BY device_feature_id
ORDER BY created_at
) AS interval
FROM t_device_feature_state
WHERE device_feature_id IN (
'eaa982b7-a3c8-4b4d-b2d0-5a5cf5245938',
'e9079170-4654-4fad-b726-23a36c793905',
'c59fca37-54f3-418b-b27c-857e08e2a0fb',
'da79df66-dcff-438e-859c-39b641fd15e9',
'5eba10ac-4c3a-479c-aba7-a1e74a00d914',
'4b5e90f0-a86b-405b-8ca1-953705ef79a3',
'c92f8fa3-d841-4692-bd3a-e5addb760a73',
'b5445f10-7aa9-41bf-8cae-d2f30498652f',
'08e90478-4bb2-4a08-986f-3d6f212c95f1',
'85311f8c-334f-4b7e-8294-2b841c0b8fe8'
)
AND created_at > TIMESTAMP '2024-12-14 10:04:11.478'
)
SELECT
device_feature_id,
MIN(created_at) AS created_at,
AVG(value) AS value,
MAX(value) AS max_value,
MIN(value) AS min_value,
SUM(value) AS sum_value,
COUNT(value) AS count_value
FROM intervals
GROUP BY
device_feature_id,
interval
ORDER BY
device_feature_id,
created_at;
Por lo tanto, he vuelto a hacer una prueba de rendimiento en el panel de control:
Estudio ChatGPT ^^:
Lectura directa de tu registro de rendimiento
Duración total
- Total ≈ 13 190 ms (13,2 s)
Distribución (panel de la izquierda)
- Visualización (Rendering) : 2 330 ms
- Renderizado (Paint / Layout) : 791 ms
- Script (JS) : 563 ms
- Carga de red : 27 ms
- Sistema / no atribuido : ~5 200 ms
- Total “útil” visible : ~4 s
- Gran hueco “no atribuido / inactivo / espera” : ~9 s
Conclusión inmediata :
no es la red,
ni DuckDB,
ni el JavaScript puro,
es mayoritariamente tiempo de espera antes de que comience el renderizado útil.
Enfoque en la parte de Red (clave para Gladys)
En tu tabla de la derecha:
- Consulta:
aggregated_states (10.5.0.227)
- Tamaño transferido : 213 ko
- Tiempo de ejecución : ~260 ms
Esto confirma lo que sospechábamos:
- la consulta backend es rápida
- el payload es razonable
- < 300 ms, por lo tanto no es el problema
Ahora podemos decir sin ambigüedad:
Los 10–13 segundos no provienen de las consultas DuckDB.
¿Dónde se pierden entonces los ~9 segundos?
Según el flame chart y la línea de tiempo:
Fase “espera / no atribuida” (~9 s)
Esto es típicamente:
- espera de un estado React completo
- espera a que todas las series estén listas
- sincronización antes del montaje del gráfico
- o lógica tipo:
- “esperar todas las promesas”
- “esperar que X se calcule antes de renderizar”
Anti-patrón clásico en los dashboards complejos.
Fase “Rendering + Layout” (~3 s)
Aquí, estamos claramente en:
- muchos puntos
- muchas series
- probablemente:
- recálculo de escalas
- recálculo de leyendas
- tooltips
- min/max
- animaciones
Es coherente con un gráfico anual multi-curvas.
Conclusión (que ya puedes formular)
Ya puedes decir, con pruebas:
Las mediciones de rendimiento de Chrome muestran que:
- la consulta backend es < 300 ms
- el payload es ~213 ko
- el JS puro < 600 ms
Los ~13 s percibidos se deben principalmente a una fase de espera + renderizado gráfico en el front.
La optimización debe hacerse mayoritariamente en el pipeline de renderizado React / gráfico, no en DuckDB.
Próximas pistas concretas (si quieres ir más allá)
Sin siquiera ver el código, los mecanismos evidentes son:
- renderizar el gráfico progresivamente (series una por una)
- limitar el número de puntos antes del renderizado (límite duro)
- desactivar animaciones / transiciones en las vistas largas
- virtualizar / canvas puro si no es ya el caso