我在postgres中有一个名为“ ts”的表,如下所示:
dev -- numeric device id
ts -- Unix epoch timestamp
key -- string (only interested in records where key is 'u')
val -- int representing uptime in ms
我将进程正常运行时间记录到此表中,并且每30秒左右记录一次。结果是表的val不断增加,当进程重新启动时,val会定期重置为0,从而创建类似锯齿的模式。请注意,实际记录的值可能不为0,因为重新启动后可能不会立即进行记录。
我想做的是通过定期挑选不代表复位前最大正常运行时间的值来清理表。同一张表中混合了多个设备,因此最长正常运行时间必须按dev分组。
示例:
dev ts key val
1 100000 'u' 50 -- boring
1 130100 'u' 30050 -- delete this
1 160100 'u' 60050 -- >> keep this one
1 190200 'u' 100 -- this record dies
1 220200 'u' 30100 -- >> keep this one too
1 250200 'u' 300
我希望查询能挑选出除我上面标记的记录以外的所有记录,这些记录没有意思,可以删除。
淘汰将在批处理过程中定期进行。
答案 0 :(得分:1)
相反,为什么不更新相关记录本身呢?并且仅在进程重新启动时才插入新记录。
答案 1 :(得分:1)
如果只想保留局部最大值,则可以使用lead()
和lag()
:
select t.*
from (select t.*,
lead(val) over (partition by dev order by ts) as next_val,
lag(val) over (partition by dev order by ts) as prev_val
from t
where key = 'u'
) t
where val > prev_val and val > next_val;
答案 2 :(得分:1)
因为它很有趣:在窗口函数中使用了新的 PostgreSQL 11 功能“ GROUPS
”来解决局部极大值的问题。
问题:
dev key ts val
1 u 100000 50
1 u 130100 30050
1 u 160100 60050 -- really single local maximum
1 u 190200 100
1 u 220200 30100 -- local maximum together with next value
1 u 250200 30100
1 u 300000 300
1 u 500000 100
1 u 550000 1000 -- a (tied) local maximum if only 1 before and 1 after is used, which is wrong
1 u 600000 1000
1 u 650000 2000 -- real local maximum together with 2 next rows
1 u 700000 2000
1 u 720000 2000
1 u 750000 300
新的PostgreSQL 11功能:
JOOQ Blog Post explains the feature
SELECT
dev, key, ts, val
FROM (
SELECT
*,
-- B:
max(val) over (order by sum, val GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) as local_max
FROM (
SELECT -- A
*,
sum(is_diff) over (order by ts)
FROM (
SELECT
*,
CASE WHEN val = lag(val) over (order by ts) THEN 0 ELSE 1 END as is_diff
FROM test t
WHERE key = 'u'
)s
)s
)s
WHERE val = local_max
A:这只是准备工作。窗口函数需要一定顺序。如果您要进行PARTITION BY val
,则该表将首先由val
进行排序。但是在此示例中,您想按ts
保留订单。然后,您想要val
的窗口函数魔术。因此,在这一部分中,我将通过保持ts
的顺序来计算紧随其后的行中相同值的组号。 (Maybe this could be done in a better way?)
结果是这样的:
dev key ts val is_diff sum
1 u 100000 50 1 1
1 u 130100 30050 1 2
1 u 160100 60050 1 3
1 u 190200 100 1 4
1 u 220200 30100 1 5 \ same group
1 u 250200 30100 0 5 /
1 u 300000 300 1 6
1 u 500000 100 1 7
1 u 550000 1000 1 8 \ same group
1 u 600000 1000 0 8 /
1 u 650000 2000 1 9 \
1 u 700000 2000 0 9 | same group
1 u 720000 2000 0 9 /
1 u 750000 300 1 10
B:这是Postgres 11的新功能。现在可以检查组的值。在过去,可以查找固定的行号。但是现在您可以检查下一组的值。说:如果您有3个具有相同值的三行,则无论您绑定多少行,都可以检查未绑定的下一个或上一个值。这样可以很酷地解决问题:
对于具有两个1000
值的示例:现在我们可以检查:下一个值是否大于当前值?不,是一样的。所以是同一组。因此,让我们看看下面的行。那是2000
,而且更大。因此,当前行不能是局部最大值。
在此组窗口中,您可以获取周围组的最大值,即使存在捆绑值,该组也可以为您提供本地值。