running average in mysql

不问归期 提交于 2019-12-02 08:32:19

问题


I have the table like below

id   timestamp  speed
1    11:00:01   100
2    11:05:01   110
3    11:10:01   90
4    11:15 :01  80

I need to calculate moving average like below

id   timestamp  speed average
1    11:00:01   100   100 
2    11:05:01   110   105
3    11:10:01   90    100
4    11:15:01   80    95

What I tried

SELECT 
*,
(select avg(speed) from tbl t where tbl.timestamp<=t.timestamp) as avg
FROM 
tbl

At first it looks quite easy but when the data on the table swell, it is too slow

Any faster approach?


回答1:


Your query is one way to do a running average:

SELECT t.*,
       (select avg(speed) from tbl tt where tt.timestamp <= t.timestamp) as avg
FROM tbl t;

The alternative is to use variables:

select t.*, (sum_speed / cnt) as running_avg_speed
from (select t.*, (@rn := @rn + 1) as cnt, (@s := @s + speed) as sum_speed
      from tbl t cross join
           (select @rn := 0, @s := 0) params
      order by timestamp
     ) t;

An index on tbl(timestamp) should further improve performance.




回答2:


Does MySQL support windowing functions?

select
  id, timestamp, speed,
  avg (speed) over (order by timestamp) as average
from tbl

If it doesn't this might work, although I doubt it's efficient:

select
  min (t1.id) as id, t1.timestamp, min (t1.speed) as speed,
  avg (t2.speed)
from
  tbl t1
  join tbl t2 on
    t2.id <= t1.id
group by
  t1.timestamp
order by
  t1.timestamp



回答3:


Or slotting neatly between GL's two answers (performancewise anyway)...

SELECT x.*, AVG(y.speed) avg
  FROM my_table x
  JOIN my_table y
    ON y.id <= x.id
 GROUP 
    BY x.id;



回答4:


What about a simple concurrent solution?

SET @summ=0; SET @counter=0;SELECT *,(@counter := @counter +1) as cnt, (@summ := @summ+speed) as spd, (@summ/@counter) AS avg FROM tbl;


来源:https://stackoverflow.com/questions/41892392/running-average-in-mysql

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!