在 SQL 表 person_rate 中,我们存储了一个随时间变化的速率浮点值。列:
id (serial, PK)
person_id (int)
date_from (date)
rate (float)
(person_id, date_from)
是独一无二的,因为每天最多允许更改一次(可能是 PK,但这并不重要)
给定 person_id 的速率值在时间域内有效,从date_from
date 到下一个 succesive 记录date_from
,或者如果没有这样的记录,则到无限未来。例子:
id person_id date_from rate
101 1 2011-01-01 100.0
145 1 2012-01-01 180.0
193 1 2012-05-01 140.0
现在我需要一个 SELECT 查询,它对每个给定的 $date都person_id
返回一个有效值。rate
假设 2012-03-01 是 180;2012-05-02 是 140 等等。
我测试过的解决方案:
1)条件date_from <= $date
+使用窗口函数rank() OVER (PARTITION BY person_id ORDER BY date_from DESC
+超选WHERE rank = 1
2) 类似于 1) 但使用SELECT DISTINCT ON (person_id)
而不是将等级限制为 1
1) 和 2) 都表现不佳,EXPLAIN 表明 db 需要对每个记录进行排序person_id
,然后首先限制为 1。可能这种类型的查询不能充分利用索引date_from
?
IDEA - 添加一个date_to
列,这会有点多余,因为该值将是“连续记录的 date_from,减去 1 天”(如果没有连续记录,则为 +infty)。但是随后的查询可能是date_from <= $date AND date_to >= $date
- 这可能会对 date_from 和 date_to 上的索引产生良好的性能。
但我有点害怕在这种情况下如何管理数据完整性 - 如何设置一个 person_id 的 [ date_from .. date_to ] 间隔不应该重叠的约束?
对于这种类型的查询,postgresql 的最佳解决方案是什么?负载是读取最多的,对 person_rate 表的写入不多。典型的查询内部需要获取每月每一天的费率......
也许这个使用 pg 9.2 上的新索引的索引/主键序数的 SQL 查询可以以某种方式提供帮助?