提高Postgresql上时间戳范围的加入速度

时间:2019-10-02 06:26:18

标签: sql postgresql

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

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

在表1上,timestamp列上有一个索引,在表2上,start | end上有一个索引(按此顺序)。当我像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),从说明中我可以看到现在索引扫描包括一个{ {1}}部分,使其变慢(从1s到14s)。

我当前正在使用的查询是:

filter

解释是

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'

3 个答案:

答案 0 :(得分:2)

这是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之前的几毫秒

答案 1 :(得分:1)

通过使用class Display extends Component { state = { bulbs: 3496, display: [] } componentDidMount () { this.createDisplay() } createDisplay = () => { const displayBoard = [] for (let i = 0; i < this.state.bulbs; i++) { displayBoard.push( <Light key={i} addColor={ this.props.addColor } color ={ this.props.color } /> ) } this.setState({display: displayBoard}) } ,可以避免对NULL的特殊处理。 (但NOT(negated_condition)解决方案更干净,IMO)


Infinity

答案 2 :(得分:0)

感谢IRC上的incognito,我找到了一个可行的解决方案,创建一个像这样的索引:

CREATE INDEX orders_timestamps ON orders (start_time,coalesce(end_time,'infinity'));

,然后将查询更改为pd.timestamp <= COALESCE(o.end_time, 'infinity')。 这样,我仍然拥有可以为空的值,并且可以使用索引值,因为我无法为NOW()编制索引,因为它是变量