报表在展现或导出时往往需要从数据库中取出大量数据,而 JDBC 的取数速度一向比较慢,有可能成为报表各运算环节的短板或瓶颈,从而严重影响整个报表的生成效率。针对这一问题,润乾报表可以利用并行计算机制(需要结合集算器实现)来显著提高 JDBC 的取数性能。
所谓并行取数是指,使用多线程技术在报表工具与数据库之间建立多个连接,同时读取一份源数据。这种读取方式需要将源数据分段,每个线程(数据库连接)读取其中一段内容,最后将所有线程的结果合并得到最终结果。这种看似复杂的方式对于润乾报表来说,可以由内置的并行机制(需要结合集算器实现)很容易完成。下面就以 oracle 为例说明实现过程。
报表描述
用户状态表展现的是明细数据,由于需要导出,必须一次性读取数据表中所有数据。单表数据量为 360 万,报表样式为:
以下为实现步骤:
编写脚本
使用集算器编写脚本(parallel.dfx),实现并行取数逻辑。首先确定分段字段,这里选择数值型的 userid 字段,再据设定的线程数和 userid 最大值(定义为大数值常量)计算每段中 userid 的范围;最后根据指定的数据范围通过 sql 分段读取数据,完成多线程取数过程。以下为实现脚本:
A | B | |
---|---|---|
1 | 2020000000L | userid 最大值不超过 2020M |
2 | 4 | 设定 4 线程 |
3 | =A1/A2 | 每线程处理的 userid 数量 |
4 | =A2.(A3*(~-1)) | 每线程处理的 userid 起始值 |
5 | fork A4 | =connect(“wm”) |
6 | =B5.query@x(“select * from t_dw_zx_account_status_day where userid>=? and userid<?”,A5,A5+A3) | |
7 | return A5.conj() |
-
A5 通 fork 使用多线程执行网格中的代码块,实现并行取数
-
B5-B6 完成并行取数,每个线程运行结果存于 B6
-
A7 为报表返回合并后的结果集
编制报表
新建报表模板后,数据集选择“集算器”,在数据集编辑窗口指定上述编辑好的 dfx 文件,完成数据集创建。
设置报表模板表达式:
A2:根据数据集 ds1 使用 select 函数取用户登录信息列表
A2-G2:根据 A2 扩展,通过取值表达式分别取用户 ID、账户、在线等信息
并行后效果
报表运行后记录数据集计算时间,并行前和并行后的运行结果比较如下:
可以看到并行取数带来的效果,通过润乾报表的并行机制可以明显加速取数过程,从而提升整体报表性能。测试结果因测试环境而异,本例的配置详见附录。
使用多线程并行取数适合数据库资源比较空闲(如连接数未达上限)的情况,能够通过并行方式充分利用数据库资源。如果数据库任务已经饱和,这种方法反而会进一步加重数据库负担,不会起到提高速度的作用。
此外,分段字段的选择对性能影响较大。最好是选择递增插入的索引字段,如作为主键的流水号,这样数据库能充分利用索引减少遍历范围;同时分段时也应尽量选择数值类型字段,作为条件的运算性能更高且易于拆分。实际操作中要综合考虑这两方面因素,本例中由于没有索引和主键,所以选择了数值型 userid。实际业务中经常能找到递增插入的有索引的数值型字段,采用并行取数的方式获得的性能提升也会更好。
【附】测试机配置
测试机型:Dell Inspiron 3420
CPU:Intel Core i5-3210M @2.50GHz *4
RAM:4G
HDD:西数 WDC(500G 5400 转 / 分)
操作系统:Win7(X64) SP1
JDK:1.6
数据库:oracle11g R2
润乾报表版本:2018