SPL 实践:跑批提速时的数据流程
跑批提速是SPL的一个主要优化场景,把跑批数据转储到SPL的高性能文件是优化过程中的重要环节。需要被转储的数据,通常包括两部分:历史冷数据和周期性增量数据(增删改)。下面介绍如何把历史与增量数据转储计算,以及周期性更新与定期重整。
一、历史数据转储
组表是SPL提供的高性能存储格式,其原理在于将数据事先排序并以压缩方式紧致存储,好处是占用空间更小,可利用有序进行快速定位。
以TPC-H的ORDERS表为例,从数据库中将历史数据转储为组表文件,代码如下:
A |
B |
|
1 |
fork 4.() |
=connect@l("oracle12c") |
2 |
=B1.cursor@x("SELECT O_ORDERKEY,O_CUSTKEY,O_ORDERSTATUS,O_TOTALPRICE,O_ORDERDATE,O_ORDERPRIORITY,O_CLERK,O_SHIPPRIORITY,O_COMMENT FROM ORDERS WHERE MOD(O_ORDERKEY,4)="/(A1-1)/"ORDER BY 1") |
|
3 |
=file("orders"/A1/".btx").export@b(B2) |
|
4 |
=directory("orders?.btx") |
|
5 |
=A4.(file(~).cursor@b()).merge(#1) |
|
6 |
=file("hisdata.ctx").create(#o_orderkey,o_custkey,o_orderstatus,o_totalprice,o_orderdate,o_orderpriority,o_clerk,o_shippriority,o_comment) |
|
7 |
>A6.append@i(A5) |
|
8 |
=A4.(movefile(~)) |
执行后,生成按主键O_ORDERKEY 有序的hisdata.ctx历史数据组表文件。
二、增量数据仅追加
2.1增量数据与历史数据整体有序
当增量数据的主键只在历史数据的主键最大值后,可以直接在历史数据后追加。
例如,历史数据组表hisdata.ctx,主键O_ORDERKEY的最大值为6000000,增量数据newdata.csv的主键从6000001开始递增:
O_ORDERKEY |
O_CUSTKEY |
O_ORDERSTATUS |
… |
1 |
36901 |
O |
… |
2 |
78002 |
O |
… |
32 |
130057 |
O |
… |
… |
… |
… |
… |
hisdata.ctx
O_ORDERKEY |
O_CUSTKEY |
O_ORDERSTATUS |
… |
6000001 |
666 |
O |
… |
6000011 |
54321 |
F |
… |
6000012 |
12345 |
O |
… |
… |
… |
… |
… |
newdata.csv
代码如下:
A |
|
1 |
=file("newdata.csv").cursor@ct() |
2 |
=file("hisdata.ctx").open().append@i(A1) |
2.2增量数据与历史数据分别有序,但不整体有序
2.2.1数据较小的情况
历史数据不大,每次与原表归并即可。
例如,历史数据组表hisdata.ctx,主键O_ORDERKEY的最大值为6000000,增量数据newdata.csv中有主键小于6000000:
O_ORDERKEY |
O_CUSTKEY |
O_ORDERSTATUS |
… |
1 |
36901 |
O |
… |
2 |
78002 |
O |
… |
32 |
130057 |
O |
… |
… |
… |
… |
… |
hisdata.ctx
O_ORDERKEY |
O_CUSTKEY |
O_ORDERSTATUS |
… |
3 |
444 |
F |
… |
500 |
66666 |
O |
… |
6000012 |
12345 |
O |
… |
… |
… |
… |
… |
newdata.csv
代码如下:
A |
|
1 |
=file("newdata.csv").cursor@ct() |
2 |
=file("hisdata.ctx").reset(;A1) |
2.2.2数据量较大
历史数据随时间增涨,每次与原表归并需要的时间变得越来越久。这时可以将数据组表文件分为两部分:历史数据组表hisdata.ctx和增量数据组表newdata.ctx,每次追加只对增量数据组表,一段时间后,再将增量数据与历史数据归并。例如,增量数据需要每天更新、每月重整:
A |
B |
|
1 |
if day(now())==1 |
=file("hisdata.ctx").reset(;file("newdata.ctx").open().cursor()) |
2 |
=file("newsdata.ctx").create@y(#o_orderkey,o_custkey,…) |
|
3 |
=file("newdata.ctx").reset(;file("newdata.csv").cursor@ct()) |
读数据时,需要将增量数据组表与历史数据组表归并后使用,例如:
=[file("newdata.ctx").open().cursor(),file("hisdata.ctx").open().cursor()].merge(#1)。
这里需要注意的是,游标序列中应按数据新旧顺序,即[增量数据,历史数据]。
如果数据量更大,可能还会涉及分区存储成复组表,可以参考:复组表定期维护例程
三、增量数据涉及修改与删除
这种情况,数据量不会非常大,我们这里只介绍单个组表上更新的方法。数据量巨大需要多个组表的情况可以使用复组表,参考:复组表定期维护例程
3.1只增加修改没有删除
当增量数据还涉及修改时,历史数据需要按主键更新。
例如,历史数据组表hisdata.ctx,主键O_ORDERKEY的最大值为6000000,另有增量数据newdata.csv:
O_ORDERKEY |
O_CUSTKEY |
O_ORDERSTATUS |
… |
1 |
36901 |
O |
… |
2 |
78002 |
O |
… |
32 |
130057 |
O |
… |
… |
… |
… |
… |
hisdata.ctx
O_ORDERKEY |
O_CUSTKEY |
O_ORDERSTATUS |
… |
1 |
1111 |
F |
… |
999 |
9999 |
O |
… |
6000012 |
12345 |
O |
… |
… |
… |
… |
… |
newdata.csv
代码如下:
A |
|
1 |
=file("newdata.csv").cursor@ct() |
2 |
=file("hisdata.ctx").reset@w(;A1) |
3.2还有删除的情况
历史数据还是上面的一样,不同的是,增量数据newdata.csv在主键O_ORDERKEY后有状态列STATUS,记录状态分为4种:B(主键变更)、D(删除)、A(更新)、I(插入),B与I必定成对出现,例如:
O_ORDERKEY |
STATUS |
O_CUSTKEY |
O_ORDERSTATUS |
… |
1 |
B |
36901 |
O |
… |
6000001 |
I |
36902 |
F |
… |
2 |
A |
123314 |
F |
… |
6000001 |
A |
36902 |
O |
… |
33 |
D |
136777 |
O |
… |
6000002 |
I |
88888 |
O |
… |
… |
… |
… |
… |
… |
6000002 |
A |
88888 |
F |
… |
… |
… |
… |
… |
… |
这种情况,需要在最初设计组表时,维字段后加个删除标识列(字段名随意,这里用DEL),其值为false代表记录有效,true代表记录作废,默认设为false。历史组表hisdata.ctx,如下:
C_CUSTKEY |
DEL |
C_NAME |
C_ADDRESS |
… |
1 |
false |
36901 |
O |
… |
2 |
false |
78002 |
O |
… |
32 |
false |
130057 |
O |
… |
33 |
false |
66958 |
F |
… |
34 |
false |
61001 |
O |
… |
… |
… |
… |
… |
… |
需要注意,在有删除标识的组表,建立时,需要用加上create@d参数,将维后的第一列作为删除标识列。
增量数据newdata.csv按状态描述,不难转为以下形式:
C_CUSTKEY |
DEL |
C_NAME |
C_ADDRESS |
… |
1 |
true |
36901 |
O |
… |
2 |
false |
123314 |
F |
… |
33 |
true |
136777 |
O |
… |
… |
… |
… |
… |
… |
6000001 |
false |
36902 |
O |
… |
6000002 |
false |
88888 |
F |
… |
… |
… |
… |
… |
… |
代码如下:
A |
|
1 |
=file("newdata.csv").cursor@ct() |
2 |
=file("hisdata.ctx").reset@w(;A1) |
带有删除标识列的组表,归并后,删除标识列为true的记录将从组表中删除。读组表时,可以在cursor中不将删除标识列读出,例如:=file("hisdata.ctx").open().cursor(o_orderkey,o_custkey,o_orderstatus,…)
英文版