【性能优化】6.4 [外键关联] 时间键
6.4 时间键
维表数据相对固定,但有时也会变动,如果不处理这个变化,就可能导致统计出错。比如想按产品产地分组汇总一段时间内的订单销售额,而产品产地可能在这段时间内发生过变化,在订单表 orders 关联产品表 product 获取产品产地时,就需要根据订单时刻决定用哪个时段的产品产地。
这样,需要在维表中增加时间字段用于存放维表记录发生变化的时刻,称为时间键。然后就可以和事实表中的时刻比对,找出合适的维表记录。但这不是一个常规的等值关联了,需要找到的是关联键相同且时间字段取值不早于指定时刻的最早者对应的记录。
用 SPL 语法写出来是这样:
D.select( id==id0 && t>=t0 ).minp( t )
其中 D 是维表,id 是原主键字段,t 是新加的时间字段,id0 和 t0 是用于查找的主键和时刻值。
事实上,因为维表记录变化会导致维表中有多个相同主键的记录,原来的主键在技术上已经不再取值唯一而不能再用作主键了,也就不能再建立索引以快速查找了,如果按上面的定义式去做遍历查找,性能将会非常低下。
一个容易想到的办法是把维表按原主键分组,每个分组成员是一个小子集,整个分组结果仍然可以看成是以原主键为主键的集合(它不再是个序表),理论上仍然可以建立索引用于快速查找,然后再用时间参数在相应的分组子集中找到合适的记录,避免遍历查找从而获得较好的性能。
SPL 对序表的主键做了扩充,实现了这个过程:
A |
|
1 |
=file("product.btx").import@b() |
2 |
>A1.keys@it(pid,dt) |
3 |
=A1.find(1,date("2020-5-1")) |
A2 建立索引时使用 @t 选项,SPL 将会用最后的字段 dt 作为时间键,之然就可以使用 find 函数来查找了。
在关联中也可以直接使用时间键:
A |
|
1 |
=file("product.btx").import@b() |
2 |
=file("orders.btx").import@b() |
3 |
>A1.keys@it(pid,dt) |
4 |
>A2.switch(p_id:dt,A1) |
5 |
=A2.groups(p_id.area;sum(p_id.price*quantity)) |
A4 的 switch 函数会使用 A2 的 dt 字段值作为时间参数去寻找维表记录。