我有一个连接两个表的查询:
- 表 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/