Pregunta

Voy a graficar los datos de flujo de red 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 un int durante segundos desde la época. Me gustaría poder hacer algo como:

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

¿Hay alguna forma de hacer esto? o, ¿sería más rápido manejarlo localmente en python? incluso para una tabla de filas de 500K?

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

¿Fue útil?

Solución 5

Utilicé 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)

También probé la solución de redondeo, pero los resultados fueron inconsistentes.

oportunidad

Otros consejos

Puede hacer esto usando división entera. No estoy seguro del rendimiento.

Deja que sea tu 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

¿Has probado lo siguiente? Simplemente divida la columna tyiem en 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é si la función ROUND () y la agrupación con llamadas a funciones funciona en MySQL, sin embargo, lo anterior es T-SQL.

FLOOR en grupo falla a veces. 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 debería agrupar como Dos grupos diferentes. Es mejor convertirlo en unsigned after floor que funciona como:

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

El problema:

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

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

Hice esto hace un tiempo, así que creé alguna función (con servidor SQL, pero supongo que es casi la misma):

Primero, creé una función escalar que me devolvía el ID de una fecha según un intervalo y una parte de la fecha (minuto, hora, día, mes, 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

Luego creé una función de tabla que me devuelve todo el ID entre 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 todos los usuarios agregados 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

GRUPO POR dbo.getIDDate (user.creation_date, 'minute', 33) ORDER BY timeTable.StartDate

:)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top