PostgreSQL generate_series奇怪的行为

问题描述

以下两个查询产生的输出完全相同:

select
  ref_date::date
from generate_series('2020-10-01','2020-10-01'::date,interval '1 day') ref_date
--   ref_date
-- 2020-10-01

select Now()::date ref_date
--   ref_date
-- 2020-10-01

但是,当在它们各自上运行explain时,我们会得到不同的结果:

# query 1
Function Scan on generate_series ref_date  (cost=0.01..12.51 rows=1000 width=4)

# query 2
Result  (cost=0.00..0.01 rows=1 width=4)

在基于ref_date的连接条件下,在连接序列中包括一个或多个连接时,情况会变得更糟:

select
  stuff
from (select ref_date::date from generate_series('2020-10-01',interval '1 day') ref_date) ref_date
left join (other_stuff) x on true
left join (more_stuff) y on y.id = x.id and y.timestamp < ref_date
-- executes in 10 minutes
-- EXPLAIN is long and complex
-- query uses index on more_stuff.(id) only
   despite an index on (id,timestamp) being available

select
  stuff
from (select Now()::date ref_date) ref_date
left join (other_stuff) x on true
left join (more_stuff) y on y.id = x.id and y.timestamp < ref_date
-- executes in ten milliseconds
-- EXPLAIN is short and simple
-- query adequately uses index on more_stuff.(id,timestamp)

实际上我不能使用Now()::date的原因是我需要generate_series()生成多个日期(例如跨5年)。

问题

是否可以使用一种替代方法,该替代方法使用日期序列,并且与上述示例中使用Now()::date时一样有效?

注意:

解决方法

相关子查询可以满足您的要求。

select stuff
FROM generate_series('2020-09-01'::date,'2020-10-01'::date,interval '1 day') as ref_date
LEFT JOIN LATERAL
(select (other_stuff)) AS x on true
left join (more_stuff) y on y.timestamp < ref_date

这将生成一个嵌套循环联接,内部计划与您的快速查询匹配。关键字LATERAL强制数据库重新评估左侧每一行的右侧。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...