[英]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.