PostgreSQL - 日期时间范围重叠

Ann*_*nna 4 postgresql performance gist-index range-types postgresql-performance

我有一个包含日期时间字段startend. 我有一个(开始,结束)项目列表。我需要检查列表中的哪些项目与表中的数据重叠。当前查询如下所示:

select br.duration from booking, (
    select tstzrange('2016-09-06 03:45:00+00', '2016-09-06 14:45:00+00') as duration 
    union select tstzrange('2016-09-06 14:45:00+00', '2016-09-06 15:45:00+00') as duration
    -- other items from my list
) as br 
where tstzrange(start, end) && br.duration
Run Code Online (Sandbox Code Playgroud)

有没有其他方法可以做到?如果我在表中有数百万行并将它们与列表中的数百个项目进行比较,您认为它会起作用吗?

Erw*_*ter 6

我建议对处理一百万行进行一些重要的改进:

SELECT br.duration
FROM  (
   VALUES 
      ('[2016-09-06 03:45:00+00, 2016-09-06 14:45:00+00)'::tstzrange)  
    , ('[2016-09-06 14:45:00+00, 2016-09-06 15:45:00+00)')
      -- more items
   ) br(duration)
WHERE EXISTS (
   SELECT FROM booking
   WHERE  tstzrange(ts_start, ts_end) && br.duration
   );
Run Code Online (Sandbox Code Playgroud)
  • 在以不必要的冗长和昂贵的形式提供您的值列表时SELECT ... UNION ...,请使用它UNION ALL,否则 Postgres 将浪费时间尝试折叠重复项。而你只需要声明的列名(S)和第一数据类型SELECT的的UNION查询。
    但是VALUES表达式更简单、更快。或者提供一个数组tstzrange[]并使用unnest()

  • 您拥有的查询将为 中的每个重叠行返回一行booking,而您很可能希望列表中的每个重叠值一次。您可以添加DISTINCTGROUP BY获取唯一的行,但这仍然会浪费时间。一个EXISTS半连接是你的情况下,更简单,更便宜的替代品之一:每行从duration如果重复条目中发现和Postgres可以停止进一步寻找此行返回一次。

  • 如果没有索引支持,查询仍然会很慢。创建功能性 GiST 或SP-GiST 索引。后者可能表现最好:

    CREATE INDEX booking_ts_range_idx on booking USING spgist (tstzrange(ts_start, ts_end));
    
    Run Code Online (Sandbox Code Playgroud)

有关的: