如何优化多数据集关联报表

本文介绍了如何优化多数据集关联报表的性能问题,特别是当数据量增大时,通过数据库的关联计算能力或使用集算器进行数据预处理。集算器提供了针对不同关联关系(多对一、一对一、一对多)的优化算法,例如外键表的外键属性化、同维表的同维表等同化、主子表的一体化关联,有效提高了报表处理速度和适用范围。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多数据集关联报表是很常见的报表形式,它允许开发者分别从不同的来源(表或数据库)分别准备数据形成不同的数据集,在报表端(模板)通过表达式描述数据集间的关系完成关联。这样可以避免在数据准备时写过于复杂的 SQL/ 存储过程,降低维护难度。尤其当报表数据来源于多个数据库时,多数据集的优势更加明显。

凡事都有两面性,多数据集为开发带来方便的同时却对性能造成了极大的影响。在报表端进行多数据集关联时要计算关联表达式(举例:ds2.select(name,,id==A1))时,报表引擎一般会采用顺序遍历的方式进行,先拿一个数据集的第一条记录去第二个数据集中遍历查找符合条件的记录,然后是第二条,第三条…。因此两个数据集关联的时间复杂度是 O(n²),数据量不大时感受还不明显,数据量稍大一些就会很慢,随着数据集数量的增多报表性能也会呈指数下降。

因此在实际报表业务中,当多数据集关联导致报表性能降低时可以考虑将多个数据集 SQL 合并成一句,利用数据库的关联计算能力提升性能。但这种方式又会导致 SQL 过于复杂,很难维护,而太复杂的 SQL 很可能被数据库搞错优化路径,结果性能仍不可控。并且合并 SQL 的方式有适用场景的限制(如无法完成跨异构库关联、文本关联等)。

下面介绍采用集算器的优化方法,写法简单且性能高,能够普遍适用于各种场景:

  1. 单数据库,多个数据集 SQL 比较复杂,很难写成一句
  2. 单数据库,多数据集中使用了存储过程,无法整合成一句 SQL
  3. 单数据库,多数据集合并成一句 SQL 后性能仍不如人意
  4. 多数据库,多数据集来源多个数据库,无法通过一句 SQL 进行查询
  5. 涉及文件数据,多数据集中部分数据来自文件,无法使用 SQL 进行统一查询

不同于 SQL(关系代数)采用笛卡尔积再过滤的方式看待 JOIN,基于离散数据集模型的集算器将关联运算做了区分(只考虑等值 JOIN):多对一的主外键表采用外键属性化方式关联、一对一的同维表采用同维表等同化方式关联、一对多的主子表采用主子表一体化关联,针对不同的表间关系采用不同算法进行运算,可以获得更简单的写法和更高的性能以及更广泛的适用范围。

我们将通过一些示例来说明面向各种情况时,如何使用集算器获得最优的实现和效率。需要说明的是,为了描述方便我们使用抽象后最简单的情况说明各种关联运算,实际业务会复杂得多,每个数据集 SQL 也会复杂得多,但是不管怎样多数据集关联关系也逃不出多对一、一对一和一对多的情况,所以拿原子操作来说明问题,以期大家遇到问题时可以采用最合适的方式处理。

报表集成

这里假定读者已经了解集算器与报表的关系,集算器仅为报表提供数据准备,将原来的多数据集通过集算器完成关联计算,将计算以结果以单 / 多数据集的方式提供给报表进行呈现。

集算器脚本可以直接被润乾报表 5.0 及以上版本直接引用(集算器数据集);如果是其他报表工具,集算器提供了标准 JDBC 和 ODBC 接口,可以采用类似调用存储过程的方式调用集算器脚本,详细可以参考教程《应用集成 - 被 JAVA 调用》章节,以及《集算器与 BIRT 集成》或《集算器与 JasperReport 集成》。

因此下面大部分例子将省略报表制作部分,主要说明集算器处理多数据集关联计算的过程。

外键表(多对一)

表 A 的某些字段与表 B 的主键关联。A 表称为事实表,B 表称为维表。A 表中与 B 表主键关联的字段称为 A 指向 B 的外键,B 也称为 A 的外键表。外键表是多对一的关系,且只有 JOIN 和 LEFT JOIN,一般不会用到 FULL JOIN。如:订单表和客户表

Orders 表和 Customer 表的主键都是其中的 id 字段,Orders 表的 customerID 字段是指向 Customer 表的外键。

这里说的主键是指逻辑上的主键(下同),也就是在表中取值唯一的字段(组),一个表上可能有多个字段(组)都取值唯一(并不常见),可以认为都是主键。不是一定是在物理表上建立的那个主键。

单外键举例

报表中有两个数据集,数据分别来自订单信息表(Orders)和客户表(Customer)(实际业务中可能是两条复杂 SQL),订单表的客户 ID 指向客户表的主键客户 ID,属于典型的主外键关系。

【计算目标】 查询某时间段内订单和客户详单

集算器数据准备

单库情况

当两个数据集来源于单个数据库,数据集 SQL 比较复杂不易合并时,通过集算器实现多对一关联计算,脚本如下:

  A B
1 =connect(“db”) / 建立数据库连接
2 =A1.query(“select * from 订单 where 订购日期 >=? and 订购日期 <=?”,begin,end) / 查询订单数据
3 =A1.query@x(“select * from 客户”) / 查询客户数据
4 >A2.switch(客户 ID,A3: 客户 ID) / 关联,在 A2 订单表客户 ID 字段上建立指向客户表的指针
5 =A2.new(客户 ID. 公司名称: 客户名称, 订单 ID, 订购日期, 运货费, 订单金额) / 通过外键属性化的方式,将外键表字段作为客户 ID 属性使用

脚本解析:

1、前 3 行连接数据库后分别取订单和客户数据作为两个独立数据集(事实上 A2 和 A3 的 SQL 可以任意复杂,取数阶段无需将两条 SQL 合并,分别查询即可);这里为了说明指针与记录,将两个表所有字段都选出,实际业务中应该用哪些字段取哪些。

2、A2 中使用了脚本参数 begin 和 end 来接收起止时间范围

3、注意 A3 的 query 函数使用了 @x 选项,代表查询后关闭连接,使用完数据库连接一定要及时关闭(也可以通过 Aclose() 显示关闭数据库连接)

4、A4 中通过 switch 函数在 A2 订单表的客户 ID 字段上建立指向客户表记录的指针实现关联

5、A5 利用建立关联关系通过“外键字段. 维表字段”的方式进行引用,如“客户 ID: 客户名称”,将维表记录看做外键的的属性,这便是外键属性化的由来;

6、A5 为报表返回关联后结果集

关于 switch 函数

在 SQL 的概念体系中并不区分外键表和主子表,多对一和一对多从 SQL 的观点看来只是关联方向不同,本质上是一回事。比如,订单也可以理解成订单明细的外键表。但是,集算器把它们区分开,在简化语法和性能优化时使用不同的手段。

switch 是集算器中实现多对一关联的函数,通过建立事实表和维表之间的外键指针实现连接。其原理是通过 HASH 算法在外键字段上建立指向维表记录的指针,这样在建立关联的时间与数据库中最快的关联方式 HASH JOIN 一样,但接下来使用连接结果时就不需要再查找 HASH TABLE,直接通过指针定位到内存中的维表记录。

建立外键指针后外键字段的原值不再存储,而被转化为指向维表记录的指针,所有维表字段都可以通过“外键字段. 维表字段”方式引用,因此 switch 函数只适合做单外键的关联(原外键字段值变了),多外键关联时需要使用 A.join 函数(后面会说明多外键情况)。

指针式连接的意义在于一次建立多次使用,重复使用时由于无需再建立连接性能高效得多。如上述例子中,除了获取订单和客户详单,还想针对客户所在区域汇总订单数量,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值