2009-10-22 34 views
6

Voy a representar gráficamente los datos netflow almacenados en una base de datos MySQL, y necesito una forma eficiente de obtener los puntos de datos relevantes. Los registros se almacenan con la fecha como int por segundos desde epoch. Me gustaría ser capaz de algo como:Grupo MySQL por intervalos en un rango de fechas

Select SUM(bytes) from table where stime > x and stime < Y 
group by (10 second intervals) 

¿Hay alguna forma de hacerlo? o, ¿sería más rápido manejarlo localmente en Python? incluso para una mesa de 500K filas?

EDIT Mi error, el tiempo se almacena como un doble sin signo en lugar de un INT. Actualmente estoy usando GROUP BY (FLOOR(stime/I)) donde I es el intervalo deseado.

Respuesta

0

He utilizado sugerencias de ambas respuestas y un compañero de trabajo. El resultado final es el siguiente:

Select FROM_UNIXTIME(stime), bytes 
from argusTable_2009_10_22 
where stime > (UNIX_TIMESTAMP()-600) 
group by floor(stime /10) 

Intenté la solución de redondeo también, pero los resultados fueron inconsistentes.

Probabilidad

2

¿Ha intentado lo siguiente? Simplemente divida la columna tyiem por 10 y redondee el resultado hacia abajo.

SELECT SUM(bytes) 
FROM  table 
WHERE  stime > x 
AND  stime < Y 
GROUP BY ROUND(stime/10, -1) 

no sé wether la función ROUND() y agrupar con la función de llamadas de obras en MySQL sin embargo, lo anterior es de T-SQL.

+0

redonda me está dando intervalos muy variables, durante un periodo de diez minutos que estoy recibiendo algunos intervalos tan tan pequeño como 7 segundos, y algunos tan grandes como 1 minuto ... – Chance

4

Puede hacer esto usando la división de enteros. No estoy seguro del rendimiento.

Deje que sea su intervalo deseado en segundos.

SELECT SUM(bytes), ((stime - X) DIV I) as interval 
FROM table 
WHERE (stime > X) and (stime < Y) 
GROUP BY interval 

Example, let X = 1500 and I = 10 
stime = 1503 -> (1503 - 1500) DIV 10 = 0 
stime = 1507 -> (1507 - 1500) DIV 10 = 0 
stime = 1514 -> (1514 - 1500) DIV 10 = 1 
stime = 1523 -> (1523 - 1500) DIV 10 = 2 
0

FLOOR en el grupo de veces falla. a veces agrupa diferentes tiempos como un valor, por ejemplo, cuando divide el valor con 3, pero no hace lo mismo cuando divide con 4, aunque la diferencia entre estos dos valores es mucho mayor que 3 o 4, que debe agruparse como dos grupos diferentes Mejor echarlo a firmar después de la planta, que funciona como:

CAST(FLOOR(UNIX_TIMESTAMP(time_field)/I) AS UNSIGNED INT) 

El problema:

veces GROUP BY FLOOR(UNIX_TIMESTAMP(time_field)/3) da menos en comparación con los grupos GROUP BY FLOOR(UNIX_TIMESTAMP(time_field)/4) que es matemáticamente no debería ser posible.

+1

Es matemáticamente muy posible. Digamos que los valores son "3" y "4", luego divididos por 3 ambos dan 1, mientras que divididos por 4 dan 0 y 1. Así que agrupar por/4 dará más grupos en este caso. – sth

0

lo hice hace poco tiempo, así que creé alguna función (con el servidor SQL, pero yo supongo que es casi lo mismo):

Primero creó una función escalar que me devuelva el ID de un día dependiendo en un intervalo y una parte de fecha (minutos, horas, días, polilla, año):

CREATE FUNCTION [dbo].[GetIDDate] 
(
    @date datetime, 
    @part nvarchar(10), 
    @intervalle int 
) 
RETURNS int 
AS 
BEGIN 
    -- Declare the return variable here 
    DECLARE @res int 
    DECLARE @date_base datetime 
    SET @date_base = convert(datetime,'01/01/1970',103) 

    set @res = case @part 
       WHEN 'minute' THEN datediff(minute,@date_base,@date)/@intervalle 
       WHEN 'hour' THEN datediff(hour,@date_base,@date)/@intervalle 
       WHEN 'day' THEN datediff(day,@date_base,@date)/@intervalle 
       WHEN 'month' THEN datediff(month,@date_base,@date)/@intervalle 
       WHEN 'year' THEN datediff(year,@date_base,@date)/@intervalle 
       ELSE datediff(minute,@date_base,@date)/@intervalle END 



    -- Return the result of the function 
    RETURN @res 

END 

Entonces creé una función de tabla que me devuelve todo el id betweend un intervalo de fechas:

CREATE FUNCTION [dbo].[GetTableDate] 
( 
    -- Add the parameters for the function here 
    @start_date datetime, 
    @end_date datetime, 
    @interval int, 
    @unite varchar(10) 
) 
RETURNS @res TABLE (StartDate datetime,TxtStartDate nvarchar(50),EndDate datetime,TxtEndDate nvarchar(50),IdDate int) 
AS 
begin 
    declare @current_date datetime 
    declare @end_date_courante datetime 
    declare @txt_start_date nvarchar(50) 
    declare @txt_end_date nvarchar(50) 
    set @current_date = case @unite 
       WHEN 'minute' THEN dateadd(minute, datediff(minute,0,@start_date),0) 
       WHEN 'hour' THEN dateadd(hour, datediff(hour,0,@start_date),0) 
       WHEN 'day' THEN dateadd(day, datediff(day,0,@start_date),0) 
       WHEN 'month' THEN dateadd(month, datediff(month,0,@start_date),0) 
       WHEN 'year' THEN dateadd(year, datediff(year,0,dateadd(year,@interval,@start_date)),0) 
       ELSE dateadd(minute, datediff(minute,0,@start_date),0) END 

    while @current_date < @end_date 
    begin 
     set @end_date_courante = 
      case @unite 
       WHEN 'minute' THEN dateadd(minute, datediff(minute,0,dateadd(minute,@interval,@current_date)),0) 
       WHEN 'hour' THEN dateadd(hour, datediff(hour,0,dateadd(hour,@interval,@current_date)),0) 
       WHEN 'day' THEN dateadd(day, datediff(day,0,dateadd(day,@interval,@current_date)),0) 
       WHEN 'month' THEN dateadd(month, datediff(month,0,dateadd(month,@interval,@current_date)),0) 
       WHEN 'year' THEN dateadd(year, datediff(year,0,dateadd(year,@interval,@current_date)),0) 
       ELSE dateadd(minute, datediff(minute,0,dateadd(minute,@interval,@current_date)),0) END 
     SET @txt_start_date = case @unite 
       WHEN 'minute' THEN CONVERT(VARCHAR(20), @current_date, 100) 
       WHEN 'hour' THEN CONVERT(VARCHAR(20), @current_date, 100) 
       WHEN 'day' THEN REPLACE(CONVERT(VARCHAR(11), @current_date, 106), ' ', '-') 
       WHEN 'month' THEN REPLACE(RIGHT(CONVERT(VARCHAR(11), @current_date, 106), 8), ' ', '-') 
       WHEN 'year' THEN CONVERT(VARCHAR(20), datepart(year,@current_date)) 
       ELSE CONVERT(VARCHAR(20), @current_date, 100) END 
     SET @txt_end_date = case @unite 
       WHEN 'minute' THEN CONVERT(VARCHAR(20), @end_date_courante, 100) 
       WHEN 'hour' THEN CONVERT(VARCHAR(20), @end_date_courante, 100) 
       WHEN 'day' THEN REPLACE(CONVERT(VARCHAR(11), @end_date_courante, 106), ' ', '-') 
       WHEN 'month' THEN REPLACE(RIGHT(CONVERT(VARCHAR(11), @end_date_courante, 106), 8), ' ', '-') 
       WHEN 'year' THEN CONVERT(VARCHAR(20), datepart(year,@end_date_courante)) 
       ELSE CONVERT(VARCHAR(20), @end_date_courante, 100) END 
     INSERT INTO @res (
StartDate, 
EndDate, 
TxtStartDate, 
TxtEndDate, 
IdDate) values(
@current_date, 
@end_date_courante, 
@txt_start_date, 
@txt_end_date, 
dbo.GetIDDate(@current_date,@unite,@interval) 
) 
     set @current_date = @end_date_courante 

    end 
    return 
end 

Entonces, si quiero contar todo el usuario agregado para cada intervalo de 33 minutos:

SELECT count(id_user) , timeTable.StartDate 
FROM user 
INNER JOIn dbo.[GetTableDate]('1970-01-01',datedate(),33,'minute') as timeTable 
ON dbo.getIDDate(user.creation_date,'minute',33) = timeTable.IDDate 

GROUP BY dbo.getIDDate (user.creation_date, 'minuto', 33) ORDER BY timeTable.StartDate

:)

1
SELECT sec_to_time(time_to_sec(datefield)- time_to_sec(datefield)%(10)) as intervals,SUM(bytes) 
FROM table 
WHERE where stime > x and stime < Y 
group by intervals 
Cuestiones relacionadas