报表应用中当数据量较大或计算过程较复杂时,会导致报表数据源准备过慢,从而影响报表性能。这时常常需要事先将报表需要的数据计算好,在呈现时直接引用即可,这样用户在访问报表时就可以迅速地获得响应。
当前的手段及弊端
由于报表在访问时还需要参数,显然不可能把所有参数组合对应的报表数据源都准备好,所以预先计算并不是最终的报表结果,在呈现的时刻仍然要再次进行一些简单的计算(如过滤、分组汇总、排序等),然而也不太可能指望报表呈现时刻由报表工具再完成所有这些运算(报表工具只能完成一部分小数据量的运算),这样就要求存储的中间数据有再次计算的能力。所以一般情况下会将中间数据采用中间表的形式存储在数据库中。
但是,使用中间表会加大数据库负担,将过多的计算工作交给数据库做,无疑会加大数据库的压力,有时反而会造成性能不升反降;而且,中间表太多还容易导致管理混乱,由于数据库采用非层次结构(与文件系统的树形结构相比),大量存在的中间表往往会引起数据库管理难题;此外,数据量稍大从数据库中读取数据还会出现I/O瓶颈,导致报表性能表现不佳。
集算报表的解决方案
集算报表的预先计算方案不需要使用数据库中间表,从而可以避免上述弊端。集算报表内置的运算引擎拥有完整的计算能力,可以允许中间数据存放在文件中,报表使用中间结果文件再次计算得到报表数据源,从而缩短报表计算时间,提升报表性能。
这种方式与使用数据库中间表有些类似,都需要事先计算准备数据,但也有很大的不同:第一,不会占用昂贵的数据库空间,不会增加数据库负担,第二,不会引起数据库组织混乱,第三,数据量大时不会出现IO瓶颈。集算报表之所以能够完成预先计算并将结果保存在文件中,得益于集算报表内置了专门用于数据计算的集算引擎及其与文件系统的无缝交互(读入和输出),可以读取多种文件格式,如常见的文本、Excel等,也包括效率更高的二进制文件,从而使文件具备再计算的能力,实现报表预先计算。
具体使用上,集算报表允许将部分甚至全部中间计算结果保存到文件中,报表被访问时通过用户给定的参数,基于结果文件再次计算最终将报表数据呈现给用户。使用集算报表进行预先计算可以通过如下步骤实现(举例说明):
1、将需要的中间结果保存成文件
中间结果计算好后可存成文件,集算报表可以支持常见的文本文件格式,例如将订单明细分组汇总后的数据存放在文本(orderDetail.txt)中,如果希望更高的性能,集算报表还可以支持更高效的二进制文件格式(比文本能快出2-5倍)。在集算器(用免费版本即可)中执行如下类似的代码可将文本文件转换成二进制格式。
file("E:/订单明细.b").[email protected](file(“E:/订单明细.txt”.cursor())
当然,生成中间数据的过程本身也可以采用集算器,但非本文关注点,此处不详述。
2、 基于中间数据文件生成报表源
集算报表可以直接基于文件数据源进行再次计算,得到报表数据源,以过滤为例。
脚本中使用的参数及其含义如下:
其中cols为选出列名,where为过滤条件(参数传递时拼接成上述格式),num为取出的记录数。
脚本内容:
上述脚本是基于最近5年订单初步汇总的中间结果进行过滤和分组汇总操作,其中:
A1:通过文件游标采用流式处理的方式读入大源文本数据,此处支持选择列,用户可以根据参数控制选出的数据列;
A2:按照指定的多个维度进行数据过滤,结果仍然是游标;
A3:根据指定的选出结果数量,使用游标取出记录;
A4:为报表返回结果集。
上述脚本是处理的一个中间结果文件,如果需要从多个文件中同时查询数据,脚本可以这样编写(以2个为例):
由于中间数据文件是按年份存储(每5年一个),如果要查询1996到2005年间的数据,需要读取2个文件,脚本中A3对两个文件的游标进行了纵向拼接,合并成一个游标,然后采用与第一个脚本相同的方式进行处理。当查询的数据范围继续扩大,需要多个文件的时候,可以通过循环的方式将多个文件游标进行纵向拼接合并。
3 、在集算报表中调用集算脚本,编辑报表表达式完成报表制作,这是报表制作的常规动作了,不再赘述。
与一般优化方式类似,预先计算也有其适用的场景。使用预先计算来提高报表性能要充分考虑计算的类型,对某些计算过程容易拆分的场景比较适合使用预先计算,如经常要对某些大表汇总数据后与其他表做连接,这样就可以先将大表汇总数据预先计算出来保存,再与其他表做连接计算;还有数据的实时性要求也要充分考虑,比如在历史查询类的报表中就比较适合使用预先计算,当然开发人员也可以采用其他手段来保证数据的实时性要求。
一般报表工具不具备针对文件的计算能力,要实现类似的效果往往要借助数据库进行,使用数据库的中间表会存在开篇我们提到的几点问题,有时会适得其反,从这个角度也充分体现了集算报表的价值。
集算报表免费版下载:http://www.raqsoft.com.cn/?p=208.