查找 Unix 时间戳之间的最新间隔

Posted

技术标签:

【中文标题】查找 Unix 时间戳之间的最新间隔【英文标题】:Find a latest gap between Unix timestamps 【发布时间】:2018-03-06 22:05:12 【问题描述】:

我目前有两个函数应该返回设备再次开始记录的时间,即前一行超过 60 秒的时间。这些功能可能工作正常,但我必须看到它永远工作。有什么捷径可以加快速度吗?

CREATE OR REPLACE FUNCTION findNextTime(startt integer)
    RETURNS integer AS
$nextTime$
DECLARE
    nextTime integer;
BEGIN
    select time into nextTime from m01 where time < startt ORDER BY time DESC LIMIT 1;
    return nextTime;
END;
$nextTime$ LANGUAGE plpgsql;

CREATE OR REPlACE FUNCTION findStart()
    RETURNS integer AS
$lastTime$
DECLARE
    currentTime integer;
    lastTime integer;
BEGIN
    select time into currentTime from m01 ORDER BY time DESC LIMIT 1;
    LOOP
        RAISE NOTICE 'Current Time: %', currentTime;
        select findNextTime(currentTime) into lastTime;
        EXIT WHEN ((currentTime - lastTime) > 60);
        currentTime := lastTime;
    END LOOP;
    return lastTime;
END;
$lastTime$ LANGUAGE plpgsql;

为了澄清,我想基本上找到任意两行之间的最后一次间隔超过 60 秒。

CREATE TABLE IF NOT EXISTS m01 (
   time integer,
   value decimal,
   id smallint,
   driveId smallint
)

样本数据: 在这种情况下,它将返回 1520376063,因为下一个条目 (1520375766) 相隔超过 60 秒。

| time       | value              | id   | driveid |
|------------|--------------------|------|---------|
| 1520376178 | 516.2              | 5116 | 2       |
| 1520376173 | 507.8              | 5116 | 2       |
| 1520376168 | 499.5              | 5116 | 2       |
| 1520376163 | 491.1              | 5116 | 2       |
| 1520376158 | 482.90000000000003 | 5116 | 2       |
| 1520376153 | 474.5              | 5116 | 2       |
| 1520376148 | 466.20000000000005 | 5116 | 2       |
| 1520376143 | 457.8              | 5116 | 2       |
| 1520376138 | 449.5              | 5116 | 2       |
| 1520376133 | 441.20000000000005 | 5116 | 2       |
| 1520376128 | 432.90000000000003 | 5116 | 2       |
| 1520376123 | 424.6              | 5116 | 2       |
| 1520376118 | 416.20000000000005 | 5116 | 2       |
| 1520376113 | 407.8              | 5116 | 2       |
| 1520376108 | 399.5              | 5116 | 2       |
| 1520376103 | 391.20000000000005 | 5116 | 2       |
| 1520376098 | 382.90000000000003 | 5116 | 2       |
| 1520376093 | 374.5              | 5116 | 2       |
| 1520376088 | 366.20000000000005 | 5116 | 2       |
| 1520376083 | 357.8              | 5116 | 2       |
| 1520376078 | 349.5              | 5116 | 2       |
| 1520376073 | 341.20000000000005 | 5116 | 2       |
| 1520376068 | 332.90000000000003 | 5116 | 2       |
| 1520376063 | 324.5              | 5116 | 2       |
| 1520375766 | 102.5              | 5116 | 2       |

【问题讨论】:

我建议你删除这个问题。提出另一个问题并提供样本数据和期望的结果。 the time when the previous row before it was less than 60 seconds 但是当上一行距离 超过 60 秒时,您的代码会返回 lastTime。请澄清。显示基本表定义(CREATE TABLE 语句)、现有索引和您的 Postgres 版本。我假设NOTICE 只是为了调试?除此之外,我想我理解这个问题。 我冒昧地修正了前导句。 【参考方案1】:

这个简单的查询应该替换您的两个函数。注意子查询中的window function lead()

SELECT *
FROM  (
   SELECT time, lead(time) OVER (ORDER BY time DESC) AS last_time
   FROM   m01
   WHERE  time < _startt
   ) sub
WHERE  time > last_time + 60
ORDER  BY time DESC
LIMIT  1;

无论哪种方式,性能的关键部分是正确的索引。最好是(time DESC)

假设time 定义为NOT NULL - 它可能应该 是,但问题中的表定义并没有这么说。否则你可能想要ORDER BY time DESC NULLS LAST - 和一个匹配的索引。见:

PostgreSQL sort by datetime asc, null first?

我希望这个 plpgsql 函数执行得更快,不过,如果差距通常会出现

CREATE OR REPLACE FUNCTION find_gap_before_time(_startt int)
  RETURNS int AS
$func$
DECLARE
   _current_time int;
   _last_time    int;
BEGIN
   FOR _last_time IN  -- single loop is enough!
      SELECT time
      FROM   m01
      WHERE  time < _startt
      ORDER  BY time DESC  -- NULLS LAST?
   LOOP
      IF _current_time > _last_time + 60 THEN  -- never true for 1st row
         RETURN _current_time;
      END IF;
      _current_time := _last_time;
   END LOOP;
END
$func$  LANGUAGE plpgsql;

呼叫:

SELECT find_gap_before_time(1520376200);

按要求得到结果。


另外:您通常可以通过将列 value 放在最后或最前面来在存储中每行节省几个字节,从而最大限度地减少对齐填充。喜欢:

CREATE TABLE m01 (
   time integer,
   id smallint,
   driveId smallint,
   value decimal
);

详细解释:

Calculating and saving space in PostgreSQL

【讨论】:

两者都按预期工作(谢谢!)原始大约需要 ~14 秒,功能 ~6 秒 @dotoconnor:很好。 (一定要有那个索引。)还要注意添加到一边。 在时间 col 上创建索引极大地改进了时间,从 6 秒缩短到大约 100 毫秒,并且还改进了正常查询,非常感谢您的提示。

以上是关于查找 Unix 时间戳之间的最新间隔的主要内容,如果未能解决你的问题,请参考以下文章

PromQL - 如何获得结果值之间的间隔

以微秒精度压缩 unix 时间戳

计算两个时间戳之间的差异并获得 unix 时间戳的差异

Mysql 之间使用,Unix 时间戳 [重复]

数组中时间戳之间的平均间隔

如何在 Python 中查找同一小时的第二天 Unix 时间戳,包括 DST?