将停车收费表交易与历史数据进

时间:2015-01-13 15:59:43

标签: sql postgresql postgresql-9.3

我从停车计时器获得实时数据,并希望将停车计时器当前状态与历史数据进行比较。我的数据包含停车票,其中datetime_start用于购买时间,datetime_stop用于何时无用。

这个SQL实际工作,但非常慢。我想我会以某种方式遍历所有数据,或者可以优化其他一些事情:

(SELECT "parking_meter_id", SUM(CASE WHEN Now() BETWEEN "datetime_start" AND "datetime_stop" THEN 1 ELSE 0 END) < ( 
SUM(CASE WHEN Now() - interval '1 week' BETWEEN "datetime_start" AND "datetime_stop" THEN 1 ELSE 0 END) + 
SUM(CASE WHEN Now() - interval '2 week' BETWEEN "datetime_start" AND "datetime_stop" THEN 1 ELSE 0 END) + 
SUM(CASE WHEN Now() - interval '3 week' BETWEEN "datetime_start" AND "datetime_stop" THEN 1 ELSE 0 END) + 
SUM(CASE WHEN Now() - interval '4 week' BETWEEN "datetime_start" AND "datetime_stop" THEN 1 ELSE 0 END) + 
SUM(CASE WHEN Now() - interval '5 week' BETWEEN "datetime_start" AND "datetime_stop" THEN 1 ELSE 0 END) + 
SUM(CASE WHEN Now() - interval '6 week' BETWEEN "datetime_start" AND "datetime_stop" THEN 1 ELSE 0 END) + 
SUM(CASE WHEN Now() - interval '7 week' BETWEEN "datetime_start" AND "datetime_stop" THEN 1 ELSE 0 END) + 
SUM(CASE WHEN Now() - interval '8 week' BETWEEN "datetime_start" AND "datetime_stop" THEN 1 ELSE 0 END) 
/ 8) AS available 
FROM "parking_meter_transactions" 
WHERE 
Now() BETWEEN "datetime_start" AND "datetime_stop" OR 
Now() - interval '1 week' BETWEEN "datetime_start" AND "datetime_stop" OR 
Now() - interval '2 week' BETWEEN "datetime_start" AND "datetime_stop" OR 
Now() - interval '3 week' BETWEEN "datetime_start" AND "datetime_stop" OR 
Now() - interval '4 week' BETWEEN "datetime_start" AND "datetime_stop" OR 
Now() - interval '5 week' BETWEEN "datetime_start" AND "datetime_stop" OR 
Now() - interval '6 week' BETWEEN "datetime_start" AND "datetime_stop" OR 
Now() - interval '7 week' BETWEEN "datetime_start" AND "datetime_stop" OR 
Now() - interval '8 week' BETWEEN "datetime_start" AND "datetime_stop" 
GROUP BY "parking_meter_id") AS transactions 

基本思路是计算截至now()的“合法”票数,并将其与当天同一时间的最后8周的票数进行比较。这可以给出一个统计概念,即是否应该有一个可用的停车位。

1 个答案:

答案 0 :(得分:1)

我建议根据

为您的查询构建覆盖索引
( datetime_start, datetime_stop, parking_meter_id )

这样,数据库就不必转到原始数据页面来完成查询。

此外,将WHERE子句调整为单个日期比较范围非常简单。在您的SUM(case)块中,是的,您需要区分它适用于哪个星期,但您的WHERE子句可以简化为类似

WHERE datetime_start > Now() - interval '2 months'

考虑一下......你的#34; NOW()&#34;打电话是不管它是什么......对于笑话,假设1月13日上午12:00。因为所有WHERE子句都是&#34; OR&#34;一起

Now - 2 months = Week of Nov 13
Now - 2 months - 1 week = Week of Nov 20
Now - 2 months - 2 weeks = Week of Nov 27
...
Now - 2 months - 8 weeks = Brings us back to Now...  

因此,您的NET时间段是开始日期/时间大于2个月之前的任何时间。

尽管如此,建议的索引应该可以显着提高性能。查看WHERE子句的复杂性,它必须继续计算日期 - 相应的间隔。由于它不能有效地利用索引,因此可能会令人窒息。

在索引中使用仪表ID将有助于GROUP BY子句优化。

每条评论的反馈。

你所有的约会都在FARTHEST,现在() - 2个月。在此之前不要考虑任何事情......但是现在我看到你额外的WHERE条款你如何只想要特定的门票&#34; NOW()&#34;按时计算,为期8周。所以where子句仍然只在单一条件下有效。

让引擎吹过该日期/时间的所有记录,而不应用复杂的WHERE条件。请记住,通过SUM(CASE / WHEN)进行的栏目选择将仅基于那些&#34; Legel&#34;在有关时间内。

SUM(CASE WHEN Now() - interval&#39; 1周&#39; BETWEEN&#34; datetime_start&#34; AND&#34; datetime_stop&#34; THEN 1 ELSE 0 END)+ SUM(现在时间为() - 间隔&#39; 2周&#39; BETWEEN&#34; datetime_start&#34; AND&#34; datetime_stop&#34;那么1 ELSE 0 END)+

所以,如果你正在寻找下午2:53这样的东西,并且你在datetime_start 7:59 pm有一个合格的WHERE子句记录,那么它将失败所有的CASE / WHEN实例和NONE结果列将添加1,从而忽略它们。

因此,即使过去2个月有10k记录,也可以通过索引快速浏览它们。您的案例/何时有资格仅计算您正在寻找的2:53(前:)时间段特定的那些,并且可能仅在所有周期内计算出314个条目。如

   Wed, Jan 14 @ 2:53
   Wed, Jan  7 @ 2:53
   Wed, Dec 31 @ 2:53
   Wed, Dec 24 @ 2:53
   Wed, Dec 17 @ 2:53
   Wed, Dec 10 @ 2:53
   Wed, Dec 3 @ 2:53
   Wed, Nov 26 @ 2:53
   Wed, Nov 19 @ 2:53