【发布时间】:2015-07-01 09:02:39
【问题描述】:
我正在运行 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(value), 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 会是更快/更清洁的方法,但也许更好的是客户端代码? 有没有更好的方法来执行这种滚动统计更新?
【问题讨论】:
-
avg(value) over (partition by sensor_id order by ts rows between 200 preceding and current row) as avg怎么样
标签: sql postgresql plpgsql window-functions