在Postgres中将时间戳截断为5分钟的最快方法是什么?

DNS*_*DNS 42 sql postgresql performance datetime

Postgres可以使用date_trunc函数对时间戳进行舍入(截断),如下所示:

date_trunc('hour', val)
date_trunc('minute', val)
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种方法将时间戳截断到最近的5分钟边界,例如,14:26:57变为14:25:00.直截了当的方式是这样的:

date_trunc('hour', val) + date_part('minute', val)::int / 5 * interval '5 min'
Run Code Online (Sandbox Code Playgroud)

由于这是查询的性能关键部分,我想知道这是否是最快的解决方案,或者是否有一些我忽略的快捷方式(与Postgres 8.1+兼容).

a_h*_*ame 15

我认为没有更快的方法.

而且我认为你不应该担心表达的表现.

执行(SELECT,UPDATE,...)语句所涉及的其他所有内容都可能比日期/时间计算更昂贵(例如,检索行的I/O).


And*_*sen 13

我想知道同样的事情.我找到了两种替代方法,但你提出的方法更快.

我非正式地对照我们的一个较大的表格.我将查询限制在前400万行.我在两个查询之间进行了交替,以避免由于db缓存而给予一个不公平的优势.


通过epoch/unix时间

SELECT to_timestamp(
    floor(EXTRACT(epoch FROM ht.time) / EXTRACT(epoch FROM interval '5 min'))
    * EXTRACT(epoch FROM interval '5 min')
) FROM huge_table AS ht LIMIT 4000000
Run Code Online (Sandbox Code Playgroud)

(注意,timestamptz即使你使用了时区unaware数据类型,也会产生这种情况)

结果

  • 运行1:39.368秒
  • 运行3:39.526秒
  • 运行5:39.883秒

使用date_trunc和date_part

SELECT 
    date_trunc('hour', ht.time) 
    + date_part('minute', ht.time)::int / 5 * interval '5 min'
FROM huge_table AS ht LIMIT 4000000
Run Code Online (Sandbox Code Playgroud)

结果

  • 运行2:34.189秒
  • 运行4:37.028秒
  • 运行6:32.397秒

系统

  • 数据库版本:x86_64-pc-linux-gnu上的PostgreSQL 9.6.2,由gcc编译(Ubuntu 4.8.2-19ubuntu1)4.8.2,64位
  • 核心:Intel®Xeon®,E5-1650v2,Hexa-Core
  • RAM:64 GB,DDR3 ECC RAM

结论

你的版本似乎更快.但对于我的具体用例来说还不够快.不必指定小时的优点使得epoch版本更加通用并且在客户端代码中产生更简单的参数化.它可以处理2 hour间隔以及5 minute间隔,而不必将date_trunc时间单元参数提升.最后,我希望将时间单位参数更改为时间间隔参数.


Erw*_*ter 9

Postgres 14开始,date_bin()最简单、最快的

\n
date_bin(\'5 min\', val, \'2000-1-1\')\n
Run Code Online (Sandbox Code Playgroud)\n

手册:

\n
\n

函数date_bin\xe2\x80\x9cbins\xe2\x80\x9d 将输入时间戳放入与指定原点对齐的指定\n间隔(步幅)中。

\n

date_bin( stride, source, origin)

\n

sourcetimestamp是or类型的值表达式timestamp with time zone。(类型的值date自动转换为\n timestamp。)stride是interval 类型的值表达式。\n返回值同样是timestampor类型timestamp with time zone,它标记\n 所在的bin 的开始位置source

\n
\n

提供匹配数据类型的“来源”,以避免由于忽略时区或假定错误的时区而导致意外结果。

\n

我的示例看起来像一个date文字,但也可以作为有效的timestamp文字。如果时间部分缺失,则假定为“00:00”。

\n

有关的:

\n\n