用于从与 Timescaledb N id 对应的表中查找时间戳的最新或最大值的 SQL 查询

Cur*_*rie 5 sql postgresql time-series lateral-join timescaledb

我在 timescale db 中有一个表 tab1,它有 3 列标签、时间、值。time 和 tag 组成了表的 pk:(time, tag)。

行数超过 500 万行。我需要找到 N 个标签中每个标签的最新时间戳或最大(时间)。

我尝试过的事情很少,我将与大家分享我的经验:

  1. 内部查询
SELECT "time", "tag", "value"
FROM tab1 
WHERE ("tag","time") IN 
(SELECT "tag", MAX("time") FROM tab1 WHERE "tag" IN(tag1,tag2) GROUP BY "tag" );
Run Code Online (Sandbox Code Playgroud)

这是给出结果,但需要大约 19 秒来执行,这超出了可接受的限制

  1. 使用时间刻度数据库中的最后一个函数
SELECT tag, last(time, time), last(value,time)
FROM tab1
WHERE "tag" IN (tag1,tag2) GROUP BY "tag" ;
Run Code Online (Sandbox Code Playgroud)

这会在 10 秒内给出输出。

我需要找到另一种类似于第二个解决方案的可行解决方案,该解决方案可能性能更好。我尝试了一些其他的东西,如 LATERAL JOIN (3)、WINDOW FUNCTIONS (ROW_NUMBER, PARTITION) (4),但解决方案并不符合预期。

  1. 使用横向给出了多列的交叉,而不是具有预期最大时间的单个值。此外,执行需要 15 秒,但这可能是由于错误的查询。
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)
Run Code Online (Sandbox Code Playgroud)
  1. 当尝试分区时,我想像这样设置限制 1 : (partition by tag order by time desc limit 1) 但它给出了语法错误。无限制 1 我没有得到最新时间。
SELECT * from 
( SELECT *, row_number() over (partition by tag order by time desc) as rownum
from  tab1) a
where tag in (tag1,tag2)
Run Code Online (Sandbox Code Playgroud)

任何人都可以建议 3,4 中的查询有什么问题,或者建议是否有其他选择。

我的表的索引是: 在此输入图像描述

dav*_*idk 5

有几件事可以帮助实现这一点,并使查询更容易、更高效。第一个,可能也是最重要的一个是表/超表上的索引 - 它需要是标签上的多列索引,时间描述 - 时间的顺序并不那么重要,但时间的顺序索引中的列非常重要。tag这里必须是第一列,因为我们需要首先按标签搜索,然后获取最新时间,如果我们有单独的索引或者首先按时间排序,这将是非常低效的。

您可以通过如下调用创建此索引:

CREATE INDEX ON tab1 (tag, "time" DESC);
Run Code Online (Sandbox Code Playgroud)

接下来是查询的制定。为每个标签获取此信息的最简单方法是编写一个DISTINCT ON查询。在 Timescale 中,我们优化了此类查询。这是一种有点奇怪的表达方式,所以可能有点难找到。

基本上你会写成这样:

SELECT DISTINCT ON (tag) tag, "time" FROM tab1 ORDER BY tag, "time" DESC;
Run Code Online (Sandbox Code Playgroud)

这应该会给你你想要的。这有点奇怪,但它会起作用!

我不会介绍其他方法,但大多数方法都会通过索引得到显着改进,但这仍然可能是性能最好的方法。

如果您愿意,请发表评论,说明其工作原理以及它是否加快了您的速度!