集算器实现外部数据并行计算

文本并行

SPL可将文本文件按体积大体分为N段,只读取其中一段。好比cardInfo.txt存储着一千万条人口信息,将其分为十份,取第二份,代码能够写做:算法

image.png

按体积大体分段,而不是按行数精确分段,目的是提升分段性能。好比在IDE中观察A2或A3的前几个字段,能够看到行数并不是精确的100万(与具体数据有关):数据库

image.png

分段读取可应用于多线程计算,从而提升读取性能。好比用2个线程分别读取cardInfo.txt,各线程计算本段行数,最后合并为总行数,可用以下代码:多线程

image.png

语句fork语句适合算法较复杂的状况,当算法比较简单时,可用cursor@m直接分段读取。好比前面的代码能够改写以下:函数

image.png

上述代码指定了线程数,若是省略线程数,则用配置文件中的“parallet limit”当作默认线程数。假设parallet limit=2,则上述代码能够改写成:性能

image.png

为了验证分段读取先后的性能差别,下面设计一个算法,分别用单线程和2线程计算cardInfo.txt的总行数,能够看到性能显著提高:spa

image.png

  JDBC 并行

经过JDBC取数时,有时会遇到数据库负载虽然不重,但取数性能仍然较差的状况,这种状况下能够用并行取数提升性能。线程

好比Oracle数据库有一张通话记录表callrecord,记录数100万条,索引字段是callTime,且数据基本按该字段平均分布。采用非并行取数时,能够发现性能不够理想,代码以下:设计

image.png

改成2线程并行取数后,能够看到性能提高明显,代码以下:索引

image.png

既然要并行取数,就要把源数据分红多个区间,使每区间的数据量大体相等。在这个例子中,索引字段是时间类型callTime,因此先用A7求出callTime的数据范围,再用A8将该范围平均分红2个时间区间。以后在A9进行并行计算,每一个线程以各自的时间区间为参数执行SQL,取数结果将大体相等。最后合并多线程的取数结果,做为最终结果。队列

函数range很是适合对数据分段。该函数可将某范围平均分为N个区间,得到第i个区间,且可根据范围的数据类型自动调整区间的数据类型。本例的范围类型是datetime,则函数range将范围按秒均分,返回类型也是datetime。若是范围类型是date,则函数range按天均分;若是范围类型是整数,则函数range按整数均分。

上面例子中,分段字段是索引,若是没有创建索引,则查询性能会出现降低。在这种状况下,并行取数仍然能够带来明显的性能提高,因此能够用相同的方法。

上面例子中,源数据基本按callTime平均分布,所以容易使各区间的数据量大体相等,若是源数据分布很不平均,能够考虑按行号分段。每种数据库都有生成行号的方法,好比oralce可用rownum。

除了单表单SQL并行取数,SPL也支持多表多SQL并行取数。好比某报表格式较复杂,须要SPL执行多个SQL,并按必定的格式拼出结果集。当采用非并行取数时,能够发现性能不够理想,代码以下:

image.png

改成4线程并行取数后,能够看到性能提高明显,代码以下:

image.png

须要注意的是,并行取数时任务数可大于并行数。好比上面代码共8个任务,但同时执行的任务只有4个,其余待执行的任务排在队列中,若是某个小任务先执行完成,SPL会从队列中取下一个任务并执行它。能够看到,当任务数较多时,即便各任务负载相差较大,也能充分发挥硬件性能。

  混合并行

当数据量太大时,除了分库计算,还能够进行混合数据源并行计算,后者性能更高。具体作法是:把数据分为两部分(或多部分),一部分存储在数据库中,一般是当前实时数据,一部分存储在组文件,一般是历史数据,再对两种数据源进行并行计算,从而得到更高性能。

好比历史订单存储在orders.ctx中,当前订单存储在数据库orcl中,请按年、月分组,对各组数据的amount字段求和。SPL代码以下:

image.png

注意fork……fork……的用法。若是fork语句块下接非fork语句块,则二者顺序执行,若是fork语句块下接fork语句块,则二者并行执行。

相关文章
相关标签/搜索