【性能优化】2.6 [外存数据集] 复组表
2.6 复组表
OLAP 业务使用的历史数据一般不会有大量频繁的更新动作,但有时历史数据的大批删除却是必要的。年代久远的数据已经失去查询分析的意义,如果继续存放在数据表中,即占用大量空间,也会影响到查询性能。但是,我们要求数据连续存储,即使本身是按时间有序的数据,要把最初时段的数据删除,也会导致所有数据要全部重写一遍,这非常耗时。
SPL 提供了复组表,允许由多个文件构成一个组表,这些文件称为复组表的分区。
A |
B |
|
1 |
=file("data.ctx":to(12)).create(#ID,dt,…;month(dt)) |
|
2 |
=file("data.ctx":[5,6,7,8,9,10,11,12]).open() |
|
3 |
=A2.cursor(…) |
创建组表时,可以设置这个组表由多个物理文件构成,每个文件会有个编号,称为分区号,即 A1 中参数的 to(12) 部分,说明组表会分成分区号为 1,2,…,12 的 12 个文件。同时给出一个从数据计算分区号的表达式,这里是 month(dt)。使用选项 append@x 追加数据时,SPL 会针对每条追加记录计算 month(dt),根据结果把数据追加到相应分区号的文件中。
使用时,可以只选择其中部分分区拼成一个逻辑组表工作,这些分区号可以不连续,但必须有序。早期数据要删除时只要把相应分区的文件删除,再打开组表时不再把这个分区加入到列表中即可,不需要重写其它分区中的数据。
特别地,在读取数据时,SPL 会再次按复组表创建时的维字段临时做归并排序,保证复组表在读出时的表现和单个组表一致,即对维字段有序,不再需要 merge 函数处理了。即上述代码中 A3 返回的游标已经可以保证对 ID 字段有序。
类似地,也可以将上节中讲到的历史数据文件和近期数据文件分别存储成复组表的两个分区(历史数据如果量很大也可以存成多个分区),这样就可以将多个文件在逻辑上作为一个组表来访问,代码会相对简洁。
上节介绍的方法不能支持实时数据追加,无论是准备出有序的新数据还是将新数据和历史数据归并,都无法实时完成。而数据在追加时,组表是不可用的。这种方法只能适应于数据可以低频离线追加的情况。
利用复组表可以实现实时性更强的追加。
将数据按时间区间级别分成若干层,比如分成 6 层:月、日、小时、分钟、秒。理想情况下,完整的复组表由各个层次的分表构成:上月以及前的月层分表、本月内昨天及以前的日层分表、当天内上一小时及以前的小时层分表、当前小时内前一分钟以及前的分钟层分表、当前分钟内的秒层分表。
最近的实时数据直接在内存中排序后存入秒层分表;积累到一分钟后,将所有秒层分表归并成分钟层分表;积累到一小时后,将分钟层分表归并成小时层分表;积累到一天后,将小时层分表归并成日层分表;积累到一个月后,将日层分表归并成月层分表。
归并时总是产生新的分表,归并过程中仍然使用当前已在存在的分表,当完成归并并启用新的分表后,即可以删除参与归并的更小的分表。即:当秒层分表向分钟层分表归并时,可以继续使用这些秒层分表,归并完成后启用了新的分钟层分表后,这些参与归并的秒层分表就可以被删除了。其它层次也是类似的。
归并和追加可以并行进行。因为在归并过程中仍有更小的分表可用,即使不能快速完成归并(数据量大的日层分表归并甚至可能需要数小时才能完成),也不会影响数据的使用,只是未归并时小分表较多,涉及到近期数据的读取性能会有受些影响。
用这种机制可以随时追加新数据进来,这些新数据和历史数据共同构成一个随时可用的复组表,保证实时追加的数据也能立即生效。复组表能保证对维字段有序的读取。实现在追加的过程中实时排序的效果。
这个过程可以全部用 SPL 代码写出来,不过其中还有不少复杂的细节,SPL 官方提供了一套完整的例程代码,可到 SPL 论坛上参考并下载。