sql - 提高 postgresql 上时间戳范围的加入速度

标签 sql postgresql

我有一个连接两个表的查询:

  • 表 1 data有一个时间戳列
  • 表 2 orders有开始和结束时间戳列

在表 1 上,我在时间戳列上有一个索引,在表 2 上,我在开始|结束上有一个索引(按此顺序)。当我像 FROM d JOIN o ON d.timestamp > o.start_ts AND d.timestamp <= o.end_ts 一样简单地加入他们时,一切都很好并且很快

问题是当订单未完成时,end_ts为空,所以我需要将我的连接更改为 d.timestamp <= COALESCE(o.end_ts, null) ,从解释中我可以看到现在索引扫描包括一个 filter使其变慢的部分(从 1 秒到 14 秒)。

我目前使用的查询是:

SELECT *
FROM data pd
JOIN orders o ON pd.timestamp > o.start_time AND pd.timestamp <= COALESCE(o.end_time, now())
WHERE pd.machine_id = 19 AND pd.name = 'somevalue' AND pd.timestamp > '2019-09-15 22:00:00' AND pd.timestamp <= '2019-09-22 21:59:59.999'

解释是

Nested Loop  (cost=0.72..162190.37 rows=1647921 width=187) (actual time=2.589..18590.362 rows=7775 loops=1)
  Buffers: shared hit=44030111 read=3348
  I/O Timings: read=20.984
  ->  Index Scan using data_timestamp_machine_id_name_unique on data pd  (cost=0.43..20237.60 rows=1730 width=81) (actual time=0.055..50.357 rows=7713 loops=1)
        Index Cond: (("timestamp" > '2019-09-15 22:00:00-07'::timestamp with time zone) AND ("timestamp" <= '2019-09-22 21:59:59.999-07'::timestamp with time zone) AND (machine_id = 19) AND ((name)::text = 'weight'::text))
        Buffers: shared hit=5132 read=3216
        I/O Timings: read=20.591
  ->  Index Scan using orders_machine_id_idx on orders o  (cost=0.29..72.52 rows=953 width=106) (actual time=2.401..2.401 rows=1 loops=7713)
        Index Cond: ((machine_id = 19) AND (pd."timestamp" > start_time))
        Filter: (pd."timestamp" <= COALESCE(end_time, now()))
        Rows Removed by Filter: 7108
        Buffers: shared hit=44024979 read=132
        I/O Timings: read=0.393
Planning Time: 0.191 ms
Execution Time: 18591.568 ms

最佳答案

这是 range types 的情况之一派上用场,因为它们会正确处理 NULL 值。

在范围上创建索引:

CREATE INDEX orders_range ON orders using gist (tsrange(start_time,end_time,'(]'));

然后在连接条件中使用相同的范围定义

SELECT *
FROM data pd
JOIN orders o ON pd.timestamp <@ ts_range(o.start_time, o.end_time, '(]')
WHERE pd.machine_id = 19 
  AND pd.name = 'somevalue' 
  AND pd.timestamp > '2019-09-15 22:00:00' AND pd.timestamp <= '2019-09-22 21:59:59.999'

不相关,但是:我会使用 pd.timestamp < '2019-09-22 22:00:00'而不是 <=时间戳为 22:00:00 之前几毫秒的运算符

关于sql - 提高 postgresql 上时间戳范围的加入速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58196206/

相关文章:

SQL FOR XML生成多个同名节点

sql - Oracle SQL - 生成并更新每行具有不同随机数的列

mysql - 在 SQL : Oldest records, 中排序,但 x 行内没有重复值

PostgreSQL:重用适用于虚拟表数据的函数代码

sql - 获得 max_value 的 postgresql 序列

ruby-on-rails - ActiveRecord 查找包括特定外来词的所有记录(不区分大小写)

sql - 计算删除SQL Server的顺序

c# - 无法为表中的标识列插入显式值

postgresql - 使用 Postgres 的 Golang UPDATE 专栏

sql - PostgreSQL - 在今天的开始时间和结束时间之间选择查询