《数据蒋堂》第9期:报表应用的三层结构

在传统的报表应用结构中,报表工具一般都是与数据源直接连接,并没有一个中间的数据计算层。确实,大部分情况下的报表开发并不需要这一层,相关的数据计算在数据源和呈现环节分别处理就够了。不过,在开发过程中,我们发现,有一部分报表的计算即不适合在数据源也不适合在呈现环节实现,这类报表在数量上并不占多数,但耗用的开发工作量占比却很大。

有过程的计算

报表工具都可以完成计算列、分组排序等运算,有些报表工具还提供了跨行组运算和相对格与集合的引用方案,可以完成颇为复杂的运算。

不过,报表工具中的运算是一种状态式的计算,也就是把所有计算表达式写在报表布局中,根据依赖关系自动处理计算次序。这种方法很直观,在依赖关系不太复杂时能一目了然地了解各单元格的运算目标。但是,在依赖关系较为复杂,数据准备计算需要分成多步时,状态式计算就困难了。如果一定要在报表中实施过程式计算,常常需要借用隐藏格,而隐藏格不仅将破坏状态式运算的直观性,还会占用更多不必要的内存。

比如要列出销售额占前一半的大客户,如果不借助数据准备环节,就要在报表中使用隐藏行列手段将不该列出来的条目隐藏,而不能直接过滤掉。再比如带明细的分组报表要按汇总值排序,需要先分组后排序,许多报表工具无法控制这个次序。

还有个典型例子是舍位平衡,明细值四舍五入后再合计,可能会与合计值的四舍五入值不相等,会造成了报表上明细与合计数值不一致,需要根据合计的舍入值倒推明细的舍入值,这种计算的逻辑并不复杂,但即便用了隐藏格也难以由报表工具完成。

多样性数据源

与多年前的单一数据源不同,现在有许多报表的数据源并不只来源于关系数据库,还可能是NoSQL数据库、本地文件、从WEB上传来的数据等。这些非关系数据库的数据源缺乏标准的数据获取接口和语法,有些甚至没有最基本的过滤能力。而计算报表时总还要进行一些过滤甚至关联运算,虽然报表工具一般都能提供这些计算能力,但由于都是内存计算,只适合于数据量较小的情况,数据量较大时就会导致容量负担过重。而且,大多数报表工具也不能很好地处理像json或XML这种多层数据,也没有灵活编码能力以登录远程WEB服务获取数据。

动态数据源也是常见的需求,报表工具使用的数据源一般事先配置好的,不能根据参数动态选择,直接使用报表工具无法实现。报表被用于通用查询时,取数用的SQL不能简单地用参数控制条件,而经常可能要替换某个子句,有些报表工具支持宏替换,能够一定程度地解决这个问题,但根据参数计算宏值也是个有条件和过程的运算,直接在报表工具中很难完成。

性能优化问题

我们在往期的文章中曾谈到过,大多数情况的报表性能问题都需要在数据准备阶段来解决,其中有许多场景都不能在数据源内部处理。比如并行取数本来就是解决数据源IO性能问题,只能在数据源外部实现;可控缓存需要在外存写入缓存信息,也不能在数据源内部处理;清单列表中的异步数据缓存和按页取数的功能,都不是数据源本身提供的能力;即使可以在数据源环节处理的多数据集关联问题,在多数据库或非数据的场景、以及希望减轻数据库负担时,仍然需要在数据源外部解决。这些无法在数据源内部处理的场景,显然也无法在报表环节处理。

数据计算层

如果把传统报表应用结构的两层改成三层,增加一个中间的数据计算层,这些问题就容易解决了。

上述的各种运算都可以在数据计算层实现,报表工具只解决呈现问题以及少量适合状态式的直观计算即可。

其实,传统报表应用结构虽然没有刻意强调数据计算层,但仍然有这一层,只是比较隐蔽。典型的实现手段就是使用数据源中的存储过程或者在应用中使用报表工具的自定义数据源接口。存储过程能够解决一些过程式计算和性能优化问题,但它只能应用于单个数据库中,相当于在数据源内部的处理,对于必须在数据源外处理的场景无能为力,有较大的局限性。自定义数据源则在理论上可以解决上述所有问题,而且几乎所有报表工具都提供有这个接口,所以这种方式的应用更为广泛。

那么,使用报表工具的自定义数据源是否就可以方便地实现数据计算层呢?我们将在下一期讨论。

原文发布时间为:2017-6-1

本文作者:蒋步星

本文来自合作伙伴“数据蒋堂”,了解相关信息可以关注“数据蒋堂”微信公众号

时间: 2024-07-28 12:44:37

《数据蒋堂》第9期:报表应用的三层结构的相关文章

【数据蒋堂】报表的数据计算层

[导读]我们在上一期[数据蒋堂]报表应用的三层结构一文中解释了报表应用结构中数据计算层的必要性,以及可以使用报表工具自定义数据源接口来实现计算层.本期我们就来讨论一下使用报表工具的自定义数据源是否可以方便地实现数据计算层以及独立计算层的优势. 在计算层中要完成一些复杂的计算逻辑,因此要有可编程的能力,而基于自定义接口可以采用报表工具的宿主语言(即用于开发报表工具的程序设计语言)进行开发,在功能方面没有问题,不过,实际应用中却仍有不少缺陷.更好的方式是实现一个显式的数据计算层,在其中提供可解释执行

【数据蒋堂】第3期:功夫都在报表外-漫谈报表性能优化

应用系统中的报表,作为面向业务用户的窗口,其性能一直被高度关注.用户输入参数后都希望立即就能看到统计查询结果,等个十几二十秒还能接受,等到三五分钟的用户体验就非常恶劣了. 那么,报表为什么会慢,又应当从哪里入手进行性能调优呢? 数据准备 当前应用中的报表大都用报表工具开发,当报表响应太慢时,不明就里的用户就会把矛头指向使用报表工具的开发人员或者报表工具厂商.其实,大多数情况报表的慢只是个表现,背后的原因是数据准备太慢,在数据进入报表环节之前就已经慢了,这时再去优化报表开发或压迫报表工具并没有用处

【数据蒋堂】第10期:报表的数据计算层

我们在上一期已经解释了报表应用结构中数据计算层的必要性,以及可以使用报表工具自定义数据源接口来实现计算层.在计算层中要完成一些复杂的计算逻辑,因此要有可编程的能力,而基于自定义接口可以采用报表工具的宿主语言(即用于开发报表工具的程序设计语言)进行开发,在功能方面没有问题,不过,实际应用中却仍有不少缺陷.更好的方式是实现一个显式的数据计算层,在其中提供可解释执行的脚本功能,把数据源计算独立出来. 我们从四个方面来分析后者的优势. 代码编写 报表工具的宿主语言一般是Java.C#等高级语言,这类语言

【数据蒋堂】功夫都在报表外--漫谈报表性能优化

应用系统中的报表,作为面向业务用户的窗口,其性能一直被高度关注.用户输入参数后都希望立即就能看到统计查询结果,等个十几二十秒还能接受,等到三五分钟的用户体验就非常恶劣了. 那么,报表为什么会慢,又应当从哪里入手进行性能调优呢? 数据准备 当前应用中的报表大都用报表工具开发,当报表响应太慢时,不明就里的用户就会把矛头指向使用报表工具的开发人员或者报表工具厂商.其实,大多数情况报表的慢只是个表现,背后的原因是数据准备太慢,在数据进入报表环节之前就已经慢了,这时再去优化报表开发或压迫报表工具并没有用处

【数据蒋堂】第15期:开放的计算能力为数据库瘦身

[数据蒋堂]第14期:计算封闭性导致臃肿的数据库 我们在上一期谈到,数据库的臃肿,也就是过多的中间表以及相关存储过程,是由于其计算封闭性造成的.如果能够实现独立的计算引擎,使计算不再依赖于数据库提供,那么就可以为数据库瘦身了. 内部来源的中间数据不必再以数据表的形式落地在数据库中,而可以放到文件系统中,由外部计算引擎提供进一步的计算能力.对于只读的中间数据,使用文件存储时不需要考虑再改写,可以更为紧致并采用一定的压缩手段,而且在访问时也不必考虑事务一致性,机制大为简化,这样能获得比数据库更好多的

【数据蒋堂】第12期:存储过程的利之弊

存储过程是数据库领域中应用非常广泛的技术,关于它的利弊讨论由来已久,我们这里针对存储过程的两个公认度较高的优点进行剖析,从而更清楚存储过程的潜在风险及应用场景. 存储过程利于界面与逻辑分离! 界面与逻辑分离是现代应用开发的一个基本准则.相对于后台数据处理逻辑,界面会有更多样性的环境,如PC.手机等,而且业务稳定性也不强,经常会改.如果能把两者分离,开发和维护界面时绑着数据处理逻辑一起改,成本就低很多. 支持存储过程的观点认为,使用存储过程能实现界面与逻辑分离.存储过程在后台数据库中运算,只要向前

【数据蒋堂】第14期:计算封闭性导致臃肿的数据库

许多大型用户的数据库(仓库)在运行多年之后,都会积累出很多的数据表,严重者数以万计.这些数据表年代久远,有些已经忘记建设原因,甚至可能已不再有用,但因为很难确认而不敢删除.这给运维工作带来巨大的负担.伴随着这些表还有大量的存储过程仍在不断地向这些表更新数据,占用大量计算资源,经常要迫使数据库扩容. 这些表是真地业务需要吗需要吗?业务会复杂到需要成千上万的表才能描述吗? 有过开发经验的人都知道这不大可能,几百个表就能描述相当复杂的业务了.这些众多的表绝大多数都是所谓的中间表,并不是用来存储基础数据

【数据蒋堂】第31期:JOIN简化 - 维度对齐

那么问题来了,这显然是个有业务意义的JOIN,它算是前面所说的哪一类呢? 这个JOIN涉及了表Orders和子查询A与B,仔细观察会发现,子查询带有GROUP BY id的子句,显然,其结果集将以id为主键.这样,JOIN涉及的三个表(子查询也算作是个临时表)的主键是相同的,它们是一对一的同维表,仍然在前述的范围内. 但是,这个同维表JOIN却不能用上一期说的写法简化,子查询A,B都不能省略不写. 可以简化书写的原因在于:我们假定事先知道数据结构中这些表之关联关系.用技术术语的说法,就是知道数据

【数据蒋堂】第27期:非常规聚合

标准SQL中提供了五种最常用的聚合运算:SUM/COUNT/AVG/MIN/MAX.观察这几个运算,我们发现它们都可以看成是一个以集合为参数返回单值的函数,我们就先把这个共同点理解为聚合运算的定义,把集合变成单值,多个值变成一个值,也就是发生了"聚合",所以叫聚合运算. 那么很显然,有集合的时候就可以应用聚合运算了,所以SUM/COUNT这些运算可以针对一个数据表(记录集合)实施. 分组运算的结果是一批分组子集,那么每个子集上也可以应用聚合运算,这也就是SQL的分组运算了.其实针对全集