繁体   English   中英

后滚动平均值

[英]Rolling average postgres

我正在运行Postgres 9.2,我有一张大桌子

CREATE TABLE sensor_values
(
  ts timestamp with time zone NOT NULL,
  value double precision NOT NULL DEFAULT 'NaN'::real,
  sensor_id integer NOT NULL
)

我有值不断进入系统,即每分钟很多。 我想保持最后200个值的滚动标准偏差/平均值,以便我可以确定进入系统的新值是否在平均值的3个标准偏差范围内。 为此,我需要当前的标准偏差,并且意味着要不断更新最后200个值。 由于表可以是数亿行,我不想让最后说200行按时间排序,然后对每个新值进行vg(值),var_samp(value)。我并假设它将更快地更新标准偏差和平均值。

我已经开始编写PL / pgSQL函数来更新滚动方差,并且对于进入特定传感器的系统的每个新值都意味着。

我可以使用代码伪像这样做

newavg = oldavg + (new_value - old_value)/window_size
new_variance += (new_value-old_value)*(new_value-newavg+old_value-oldavg)/(window_size-1)

这是基于http://jonisalonen.com/2014/efficient-and-accurate-rolling-standard-deviation/

基本上窗口的大小为200。 old_value是窗口的第一个值。 当一个新值出现时,我们将窗口向前移动一个。 得到结果后,我为传感器存储以下值

The first value of the window.
The mean average of the window values.
The variance of the window values.

这样我就不必经常获得最后200个值并做总和等。当新的传感器值进入时,我可以重复使用这个值。

我的问题是,第一次运行时我没有传感器的先前窗口数据,即上面的三个值,所以我必须以缓慢的方式进行。

就像是

WITH s AS
        (SELECT value FROM sensor_values WHERE sensor_values.sensor_id = $1  AND ts >= (NOW() - INTERVAL '2 day')::timestamptz ORDER BY ts DESC LIMIT 200)
    SELECT avg(value), var_samp(value)  INTO last_window_average, last_window_variance FROM s;

但是我怎样才能从select语句中获取最后一个值(最早)? 我可以从PL / pgSQL中的s访问第一行吗?

我认为PL / pgSQL会更快/更清洁,但也许更好的做法是客户端代码? 滚动统计更新是否有更好的方法来执行此类型?

我假设,每次使用适当的索引重新计算最新的200个条目并不会非常缓慢。 如果你要做一个索引,比如:

CREATE INDEX i_sensor_values ON sensor_values(sensor_id, ts DESC);

你将能够很快得到结果:

SELECT sum("value") -- add more expressions as required
  FROM sensor_values
 WHERE sensor_id=$1
 ORDER BY ts DESC
 LIMIT 200;

您可以在PL/pgSQL函数的循环中执行此查询。 如果您将很快迁移到9.3(或更高版本),您还可以使用LATERAL连接来实现此目的。

我不认为覆盖索引在这里会有好处,因为表不断变化而且IndexOnlyScan不会启动。

最好还检查松散索引扫描

PS列名称value应该是双引号,因为这是一个SQL保留字

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM