使用current_date :: date而不是硬编码日期,Postgres查询非常慢

时间:2009-09-29 23:01:32

标签: sql postgresql

我对PostgreSQL 8.3运行了相当长而复杂的SQL查询。部分查询涉及对今天结束的日期范围进行过滤,如下所示:

where ...
  and sp1.price_date between current_date::date - '1 year'::interval and current_date::date
  and sp4.price_date between current_date::date - '2 weeks'::interval and current_date::date
  and sp5.price_date = (select sp6.price_date 
                          from stock_prices sp6 
                         where sp6.stock_id = s.stock_id 
                           and sp6.price_date < current_date::date 
                      order by sp6.price_date desc 
                         limit 1)
  ...

此查询需要大约5分钟才能运行(第一次),第二次大约需要1.5分钟。通过查看EXPLAIN ANALYZE输出,似乎 current_date 是问题所在。所以我尝试用硬编码的日期替换它,如下所示:

where ...
  and sp1.price_date between '2009-09-30'::date - '1 year'::interval and '2009-09-30'::date
  and sp4.price_date between '2009-09-30'::date - '2 weeks'::interval and '2009-09-30'::date
  and sp5.price_date = (select sp6.price_date 
                          from stock_prices sp6 
                         where sp6.stock_id = s.stock_id 
                           and sp6.price_date < '2009-09-30'::date 
                      order by sp6.price_date desc 
                         limit 1)
  ...

然后查询运行半秒钟!这很好,除了日期在查询中总共有10个位置,当然,我不希望用户必须在10个地方手动更改它。在MS SQL Server中,我只是声明一个具有当前日期值的变量并使用它,但apparently在Postgres中的普通SQL中是不可能的。

如何在自动使用当前日期的同时快速运行此查询?

2 个答案:

答案 0 :(得分:2)

首先,在两个变体上发布EXPLAIN ANALYZE,以便我们看到。第一步,弄清楚为什么一个比另一个慢。查看整个查询也可能很有用。

第一个变体应该是可优化的。

如果没有让您的用户在多个地方更改您的查询,请考虑撰写stored procedure,或者在优化第一个变体时,/ view

编辑:注意到你的current__date - '...':: interval会返回一个没有时区的时间戳。我假设您想要转换为日期:(current_date - '2周':: interval):: date

答案 1 :(得分:1)

编辑:以下测试但是它比原始查询运行得更慢!    关于这一点的教训可能是所有类型转换(:: date,:: interval等)都会导致性能损失。也许这些显式的强制转换可以某种方式被其他东西取代,并且还可以预先计算一些表达式,例如'D.RightNow :: date - '1 year':: interval'。

- 原始回复 -
您可以将当前日期插入另一个空表中并加入该表...

换句话说,假设创建了这样一个表并命名为tblNow,那么带有与日期相关的过滤器的查询可能会变成这样:

UPDATE tblNow SET RightNow = TIMEOFDAY();  
-- note: above could use CURRENT_DATE  or whatever date function matches the
-- semantics of the date fields in other tables.

-- and now the original query can become

from ...
join tblNow AS D ON 1=1 -- added join
                   -- then all current_date::date below changed to D.RightNow

where ...
  and sp1.price_date between D.RightNow::date - '1 year'::interval and D.RightNow::date
  and sp4.price_date between D.RightNow::date - '2 weeks'::interval and D.RightNow::date
  and sp5.price_date = (select sp6.price_date 
                          from stock_prices sp6 
                         where sp6.stock_id = s.stock_id 
                           and sp6.price_date < D.RightNow::date 
                      order by sp6.price_date desc 
                         limit 1)
  ...

每次我们希望在当前时刻运行它时,有效地要求 no 编辑查询。我不熟悉postgreSQL,但这种方法对于在SELECT语句中使用变量的任何限制都是一种自然的解决方法。