Pergunta

Vou ser graficamente dados NetFlow armazenados em um banco de dados MySQL, e eu preciso de uma maneira eficiente para obter os pontos de dados relevantes. Eles registros são armazenados com a data como um int para segundos desde época. Eu gostaria de ser capaz de algo como:

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

Existe uma maneira de fazer isso? ou, seria mais rápido para lidar com isso localmente em python? mesmo para uma mesa 500K linha?

Editar Meu erro, o tempo é armazenado como um sem assinatura de casal em vez de uma INT. Atualmente estou usando GROUP BY (FLOOR(stime / I)) onde I é o intervalo desejado.

Foi útil?

Solução 5

Eu costumava sugestões de ambas as respostas e um colega de trabalho. O resultado final é a seguinte:

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

Eu tentei a solução arredondamento bem, mas os resultados foram inconsistentes.

Possibilidade

Outras dicas

Você pode ser capaz de fazer isso usando divisão inteira. Não tenho certeza do desempenho.

Seja I o intervalo desejado em 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

Você já tentou o seguinte? Apenas dividir a coluna tyiem por 10 e em volta do baixo resultado.

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

Eu não sei wether a função ROUND () e agrupamento com chamadas função funciona no MySQL, porém, o acima é T-SQL.

FLOOR no grupo por vezes falha. TI vezes, por vezes grupos diferentes como um valor, por exemplo, quando você divide o valor com 3 mas não fazer o mesmo quando você divide com 4, embora a diferença entre estes dois valores é muito maior do que 3 ou 4, que deveria grupo como dois grupos diferentes. Melhor lançá-lo aos não assinado depois de andar que funciona como:

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

O problema:

Às vezes GROUP BY FLOOR(UNIX_TIMESTAMP(time_field)/3) dá menos grupos em comparação com GROUP BY FLOOR(UNIX_TIMESTAMP(time_field)/4) que é matematicamente não deveria ser possível.

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

Eu fiz isso há pouco tempo, então eu criei alguma função (com o SQL Server, mas eu suponho que é quase o mesmo):

Primeiro eu criei uma função escalar que me devolver o ID de uma data de acordo com um intervalo e uma parte da data (minuto, hora, dia, traça, ano):

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

Em seguida, eu criei uma função de tabela que retorna-me todo o id betweend um intervalo de datas:

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

Então, se eu quero contar tudo que o usuário adicionado 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, 'minutos', 33) ORDER BY timeTable.StartDate

:)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top