[英]SQL query for finding latest or max value of timestamp from table corresponding to N ids Timescaledb
我在时间刻度数据库中有一个表 tab1,它有 3 列标记、时间、值。 time 和 tag 构成了表的 pk:(time, tag)。
有超过 500 万 (50 000 000) 行。 我需要为 N 个标签中的每一个找到最新的时间戳或最大(时间)。
我尝试了一些东西,我将与每个人分享我的经验:
SELECT "time", "tag", "value"
FROM tab1
WHERE ("tag","time") IN
(SELECT "tag", MAX("time") FROM tab1 WHERE "tag" IN(tag1,tag2) GROUP BY "tag" );
这给出了结果,但执行时间大约为 19 秒,这超出了可接受的限制
SELECT tag, last(time, time), last(value,time)
FROM tab1
WHERE "tag" IN (tag1,tag2) GROUP BY "tag" ;
这将在 10 秒内给出 output。
我需要找到另一个类似于第二个可能表现更好的可行解决方案。 我尝试了一些其他的东西,比如 LATERAL JOIN (3), WINDOW FUNCTIONS (ROW_NUMBER, PARTITION) (4) 但解决方案并不像预期的那样。
SELECT table1."tag", table1."time",table1."value" from tab1 as table1
join lateral (
SELECT table2 ."tag",table2 ."time" from tab1 as table2
where table2."tag" = table1."tag"
order by table2."time" desc limit 1
) p on true
where table1."tag" in (tag1,tag2)
SELECT * from
( SELECT *, row_number() over (partition by tag order by time desc) as rownum
from tab1) a
where tag in (tag1,tag2)
任何人都可以建议 3,4 中的查询有什么问题或建议是否有其他选择。
有几件事情会对此有所帮助,并使此查询更容易、性能更高。 第一个,可能也是最重要的一个是表/超表上的索引——它需要是标签上的多列索引,time desc——时间的顺序并不重要,但顺序索引中的列很重要。 tag
必须是这里的第一列,因为我们需要先按标签搜索,然后获取最新时间,如果我们有单独的索引或者如果我们先按时间排序,这将是非常低效的。
您可以通过这样的调用创建此索引:
CREATE INDEX ON tab1 (tag, "time" DESC);
接下来是查询的制定。 为每个标记获取此信息的最简单方法是编写一个DISTINCT ON
查询。 在 Timescale 中,我们优化了这种查询。 制定它的方式有点奇怪,因此可能有点难以找到。
基本上你会这样写:
SELECT DISTINCT ON (tag) tag, "time" FROM tab1 ORDER BY tag, "time" DESC;
那应该给你你想要的。 这有点奇怪,但它会起作用!
我不会通过其他方法达到 go,但大多数方法都会通过索引得到显着改进,但这仍然可能是性能最高的方法。
如果你愿意,请发表评论,说明它是如何工作的,以及它是否为你加快了速度!
所以想出了其他两种方法:
SELECT distinct t_outer.tag, t_top.time, t_top.value from tab1 t_outer join lateral ( SELECT * from tab1 t_inner where t_inner.tag = t_outer.tag order by t_inner.time desc limit 1) t_top on true where t_outer.tag in (标签 1)
这可行,但处理时间超过 14 秒。
SELECT * FROM (SELECT tag,time,"value", rank() OVER (PARTITION BY tag order by time desc ) as RN FROM tab1 WHERE tag IN(tag1) ) 作为结果 WHERE results.RN=1;
这也有效并且需要大约 9 秒的时间来处理。
比较结果时,即使对于单个标签,内部查询和横向查询也是性能最差的查询。 所以他们被淘汰了。
到目前为止,Last() 和 Partition() 查询是我们的主要竞争者。 如果获取的列越少,Last() 的性能就越好,否则,如果我们获取所有列,则两者的执行时间相当。
我想补充的一点是,使用 ORDER BY LIMIT 查询比所有选项的执行方式都好(单个标签的执行时间少于 1 秒),但缺点是它不适用于多个标签输入。 因此,如果您需要查询单个标签并具有类似的数据库配置,您可以尝试这样做。
我想在这里为 David 的出色回答添加一些内容,那就是理解为什么列顺序对您的查询很重要。
您的主键实际上是一个多列 b 树索引。 这意味着要使用索引,查询必须先遍历时间列,然后才能检查标签列。 就您而言,这对您不是很有帮助。 您希望能够做的是首先遍历标签,然后获取最近的时间。
为此,您必须首先在您的 btree 列表中拥有该标签。 我不知道 asc 或 desc 是否会在这里产生很大的不同,因为 PostgreSQL 可以在任一方向上搜索索引,并且您按时扫描的方向不取决于您扫描标签的方向。 然而,跳过扫描的时间尺度优化可能会发生,因此最好遵循该建议。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.