复杂报表使用分页标签解决性能问题特例
概述:
性能问题在报表解决方案中是一个倍受关注的问题,最容易引发性能问题的就是大数据量的处理,一下子处理上十万级的数据什么样的服务器都会出现内存不足,溢出的现象,针对这个问题润乾报表提供了一个非常强力的解决方案:extHtml分页标签,以页为单位,分批从数据库中取数据(例如一次取十条记录),利用这个原理,所有大数据量问题都可以迎刃而解了。
extHtml分页标签有5个属性:
totalCountExp–总记录数(必填属性)
totalCountExp=”query(‘SELECT count(*) FROM table1′)”
通过上面的语句计算出所要展示的数据表(table1)中一共有多少条数据记录
pageCount–每页记录数(非必填)
每次从数据库中取出的记录条数,如果设为10,则每次(每页)只从数据库中取10条数据用于展示和打印。默认值为20。
rowsPerRecord–每条记录所占行数(主要用于自由报表)
如果一条记录构成一个自由报表,占5行,就需要把这个属性设成5,则每页会扩展出pageCount* rowsPerRecord行来展示数据,即10*5行。
startRowParamName/ endRowParamName–起始行参数名/结束行参数名(非必填)
通过这5个属性就可以很好的解决大数据量的问题了,但是这个标签最初的设计是用在行式报表和自由报表上的(即数据库中的一条记录正好可以生成一行报表,或者一个自由报表,具体的形式可以参考分页标签的教程),那复杂的报表能否使用这个标签呢,比如说主子报表,分组报表等,本文就用一个客户的实际案例来解开这个疑问。
客户问题模拟重现:
操作系统: windows 应用服务器:tomcat 数据库:DB2 产品:润乾4.0版
Mis中客户原问题ID:3552(客户报表原件在问题附件中)
模拟设计客户报表样式:
客户的报表中有两个特殊的地方,多层分组排序和主子报表,这两个地方都会对分页标签的使用造成影响,下面一一说明:
多层分组排序的问题:
举一个例子,假如数据库中的数据是这样无序存储的:3,1,2,4,5,我们在报表展示的时候使用了group排序,报表会把数据取出来并排序展示:1,2,3,4,5,但是打印的时候却还是直接从数据库取数,没有排序,也就是打印预览还是:3,1,2,4,5,所以使用分组排序就造成了展示和打印的不匹配。
解决方案:在数据库中提前排好序,使得打印取数也按顺序来。
主子报表的问题一:
使用分页标签后每页展示的行数是固定的,即每页pageCount* rowsPerRecord行,主子报表的行数多于或少于这个行数都会造成报表展示混乱,所以主子报表的行数应该做成固定行和扩展行的和正好是pageCount的倍数,如例子中pageCount=”7″,可以把报表设计成14行,这样rowsPerRecord=”2″就正好匹配了。一页正好显示一个完整的主子报表。相当于把主子报表变成了一个每条数据占两行的自由报表。
主子报表的问题二:
客户在设计主子表的时候运用了一个技巧,子表按分组显示,每页只展示7行,多则分到下页展示,少则补空行,这样就又出现了与分页标签冲突的地方,我们继续用例子说明,数据库中数据如下图:
因为每次展现7条记录,所以我们设pagecount=”7″,即每次展示和打印都取7条数据,但是展示的时候报表强制按组展示,如上图中的数据在web展示的时候第一页是4条记录加3行空行。但是打印的时候没有展示时的格式限制,打印预览的第一页会从数据库中取7条记录,这样就造成了展示和打印的不匹配。
解决方案:
先在在数据库中补空数据行,把各组的数据都补成7的倍数,如下图所示:
这样web展示的时候会正好取7条记录(包含3条空记录)并展示7条,打印预览的时候也会正好取7条记录(包含3条空记录),展示和打印就可以对应上了。
补空数据的大致思路:(本思路只供参考,客户可以使用自己的方法来补)
判断每个分组中的记录数是否是7的倍数,如果是则不补,如果不是则计算缺多少条记录并补齐。
操作步骤:
第一步:新建一个数据表,并插入测试数据。
CREATE TABLE NULLID.TEST (
DQ VARCHAR (10) NOT NULL , //地区
CS VARCHAR (10) NOT NULL , //城市
DINGDANID INTEGER NOT NULL , //订单ID
CHANPINID INTEGER NOT NULL , //产品ID
TJ INTEGER ) //条件,用于补空行判断
如果是对已有数据表操作,则需要对数据表补一个字段:tj integer,并把初始值都设为1。表数据如下:
第二步:建立一个临时表,用于判断需要补多少条数据
create table lsb1 (id integer ,id1 integer)
表结构为:
id id1
0 1
0 2
0 3
0 4
5
6
0 7
第三步,执行补空判断语句:
select dq,cs,dingdanid,0,0 from (
SELECT a.dq,a.cs,a.dingdanid,(7-mod(count(a.chanpinid),7)) as ss from NULLID.TEST a
group by a.dq,a.cs,a.dingdanid
having (7-mod(count(a.chanpinid),7))>0 and 7-mod(count(a.chanpinid),7) < 7) a1
left join NULLID.lsb1 b on a1.ss>=b.id1
union all
select * from NULLID.TEST order by dq,cs,dingdanid
代码解释:
红色代码部分为判断每组数据相对于7的倍数差多少条记录,执行后返回结果见下图:
黄色底色代码部分为通过左连接红色代码的执行结果和临时表生成所要补入的空行部分,执行结果见下图:
union all 的作用是把原数据和要补的数据合并起来,这样就完成了补空行的操作。合并后效果 见下图:
这就是复杂报表使用分页标签的一个特例,虽然过程比较复杂,但是却可以解决大数据量的性能问题,以后再遇到类似的报表就可以用这个方法解决了。