|批量随机键值的查询优化( 三 )


如果键值数据有比较明显的业务特征 , 我们可以考虑按照实际业务场景使用日期、部门之类的字段来对数据进行拆分 。 如:将属于部门 A 的 1000 条记录均分在 10 份数据中 , 每份数据就有 100 条记录 。 在利用多线程查询属于部门 A 的记录时 , 每个线程就会从各自对应的数据中取数相应的这 100 条记录了 。
对于没有什么特征的数据 , 尤其是随机数 , 可以考虑按整数的尾数取余数来分成 N 份数据 。 这样可以尽可能地确保每份数据中数据量的均匀分配 。
4.2 举例
|批量随机键值的查询优化
本文插图

基于以上数据结构 , 数据拆分以及建立组表:
|批量随机键值的查询优化
本文插图

A2:使用循环函数 , 创建名为“键值名 _ 键值取 N 的余数.ctx”的组表文件 , 其结构同为 (#id,data) 。
A3:用循环函数将游标数据分别追加到 N 个原组表上 。 此处 N 为参数 , 假设 N=4 , 当循环第一次时 , 拼出的 eval 函数参数为:channel(A1).select(id%4==0).attach(A2(1).append(~.cursor())) 。 意思是对游标 A1 创建管道 , 将管道中记录按键值 id 取 4 的余数 , 将余数值等于 0 的记录过滤出来 。 attach 是对当前管道的附加运算 , 表示取和当前余数值对应的原组表 , 将当前管道中筛选过滤出的记录 , 以游标记录的方式追加到 A2(1) , 即第 1 个组表 。
多线程并行创建索引:
|批量随机键值的查询优化
本文插图

A1:使用 fork 执行多线程时 , 需要注意环境中的并行限制数是否设置合理 。
多线程并行查询:
|批量随机键值的查询优化
本文插图

需要注意的是 , 将待查找的批量键值用和拆分组表数据同样的规则拆分后 , 在各自对应的组表中进行查找 。 并且取数动作应当在多线程并行内完成 , 而不是将各自的游标返回后再取数 。
五、 数据追加
对于大数据来说 , 新数据的追加是不可避免的 。 数据追加通常要考虑原数据与追加数据的关系 , 较简单的情况是连续有序的数据 , 直接在原数据尾部追加新数据 , 对追加后的数据 , 还需要更新索引 。 如果新数据与原数据 , 整体不是连续有序 , 就需要在追加数据时做归并运算 , 并随后更新索引 。 尤其是当原数据变得很大时 , 原数据与新数据的频繁归并、每次追加后更新索引 , 都会带来极高的时间成本和磁盘损耗问题 。
这种情况可以建立一份临时数据区来存放每次追加的新数据 , 当这个临时数据区达到一定规模(在数据增量较为稳定的情况下也可以按时间来决定 , 比如每个月初) , 就将临时数据区(小数据)与原数据(大数据)进行一次归并 , 并更新索引 。 查找时可以将大小两份数据在逻辑上合并为一份数据后进行查找 。
无序的数据追加时 , 因为索引就是排序的 , 要重建索引也会面临以上有序数据追加时的问题 , 还是需要大小两份数据的办法 , 等积累多了再重建索引 。
5.1 举例
|批量随机键值的查询优化
本文插图

SPL提供了补文件的功能 , 可以方便地应对复杂的数据追加场景 。
单个文件时 , 利用补文件追加数据:
|批量随机键值的查询优化
本文插图

A1:add.txt 是新增数据(这里假设数据来自文本文件 , 实际也可能来自数据库等其他数据来源) , 与已有文件结构相同 , 均为 (#id,data) , 其中 id 有序 。


推荐阅读