PSQL - 在两个单独的字段上按间隔过滤查询的性能

PSQL - Performance of query filtered by intervals on two separate fields

我有一个涵盖时间间隔的 PostgreSQL table。

这是我的table

的简化结构
CREATE TABLE intervals (
  name        varchar(40),
  time_from   timestamp,
  time_to     timestamp
);

table 包含数百万条记录,但是,如果您在过去的特定时间点应用过滤器,

的记录数
time_from <= [requested time] <= time_to

数量总是非常有限(不超过 3k 个结果)。所以,像这样的查询

SELECT *
FROM intervals
WHERE time_from <= '2020-01-01T10:00:00' and time_to >= '2020-01-01T10:00:00'

应该是 return 相对少量的结果,理论上,如果我使用正确的索引,它应该很快。但是一点也不快

我尝试在 time_from 和 time_to 上添加组合索引,但引擎没有选择它。

Seq Scan on intervals  (cost=0.00..156152.46 rows=428312 width=32) (actual time=13.223..3599.840 rows=4981 loops=1)
  Filter: ((time_from <= '2020-01-01T10:00:00') AND (time_to >= '2020-01-01T10:00:00'))
  Rows Removed by Filter: 2089650
    Planning Time: 0.159 ms
    Execution Time: 3600.618 ms

为了加快查询速度,我应该添加什么类型的索引?

btree 索引在这里效率不高。它可以快速丢弃 time_from > '2020-01-01T10:00:00' 的所有内容,但这可能不是 table 的全部(至少,如果你的 table 可以追溯到很多年前)。一旦以这种方式消耗了索引的第一列,就不能非常有效地使用下一列。它只能跳转到 time_from 关系中 time_to 值的特定部分,这不是很有用,因为可能没有那么多关系。 (至少,它不能在计划查询时证明自己)。

你需要的是gist索引,专门针对这种多维度的东西:

create extension btree_gist ;
create index on intervals using gist (time_from,time_to);

该索引将支持您所写的查询。另一种可能性是对时间范围进行索引并对其进行索引,而不是将开始点和结束点分开。

-- this one does not need btree_gist.
create index on intervals using gist (tsrange(time_from,time_to));

但是这个索引迫使您以不同的方式编写查询:

SELECT * FROM intervals
WHERE tsrange(time_from,time_to) @> '2020-01-01T10:00:00'::timestamp