如何提高报表的取数性能

报表在展现或导出时往往需要从数据库中取出大量数据,而 JDBC 的取数速度一向比较慢,有可能成为报表各运算环节的短板或瓶颈,从而严重影响整个报表的生成效率。针对这一问题,润乾报表可以利用并行计算机制(需要结合集算器实现)来显著提高 JDBC 的取数性能。

所谓并行取数是指,使用多线程技术在报表工具与数据库之间建立多个连接,同时读取一份源数据。这种读取方式需要将源数据分段,每个线程(数据库连接)读取其中一段内容,最后将所有线程的结果合并得到最终结果。这种看似复杂的方式对于润乾报表来说,可以由内置的并行机制(需要结合集算器实现)很容易完成。下面就以 oracle 为例说明实现过程。

报表描述

用户状态表展现的是明细数据,由于需要导出,必须一次性读取数据表中所有数据。单表数据量为 360 万,报表样式为:

imagepng

以下为实现步骤:

编写脚本

使用集算器编写脚本(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 文件,完成数据集创建。

设置报表模板表达式:

imagepng

A2:根据数据集 ds1 使用 select 函数取用户登录信息列表

A2-G2:根据 A2 扩展,通过取值表达式分别取用户 ID、账户、在线等信息

并行后效果

报表运行后记录数据集计算时间,并行前和并行后的运行结果比较如下:

imagepng

可以看到并行取数带来的效果,通过润乾报表的并行机制可以明显加速取数过程,从而提升整体报表性能。测试结果因测试环境而异,本例的配置详见附录。

使用多线程并行取数适合数据库资源比较空闲(如连接数未达上限)的情况,能够通过并行方式充分利用数据库资源。如果数据库任务已经饱和,这种方法反而会进一步加重数据库负担,不会起到提高速度的作用。

此外,分段字段的选择对性能影响较大。最好是选择递增插入的索引字段,如作为主键的流水号,这样数据库能充分利用索引减少遍历范围;同时分段时也应尽量选择数值类型字段,作为条件的运算性能更高且易于拆分。实际操作中要综合考虑这两方面因素,本例中由于没有索引和主键,所以选择了数值型 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