润乾报表使用Oracle分页存储过程实现大数据量报表分页查询
应用背景
海量数据的报表在读取访问过程中可能会出现速度过慢、内存溢出、系统死机等问题,润乾目前提供的分页标签有两种标签:extHtml和aotuBig标签可以很好的支持报表的分页读取、展现及导出。此种方式在发布报表的时候需要用不同于html标签,需要在报表展现的页面上调用分页标签进行报表发布。
本文采用了oracle存储过程+普通报表模板的方式能够实现大数据量报表的分页读取,利用oracle存储过程实现分页,在报表模板中使用分页查询结果,报表发布页面仍然使用润乾html标签(普通报表发布页面,如润乾提供的showReport.jsp页面)。 该方式采用另一种思路实现了海量数据报表的分页访问,提升报表查询展现速度。
实现方案
1.测试数据建立:
利用如下sql在数据库中生成50万条测试数据
create table myTestTable as
select rownum as id,
to_char(sysdate + rownum/24/3600, ‘yyyy-mm-dd hh24:mi:ss’) as inc_datetime,
trunc(dbms_random.value(0, 100)) as random_id,
dbms_random.string(‘x’, 20) random_string
from dual
connect by level <= 500000;
2.建立数据库存储过程:
oracle中建立分页存储过程fenye
create or replace package testpackage as
TYPE test_cursor is ref cursor;
end testpackage;
create or replace procedure fenye
(
p_cursor out testpackage.test_cursor,–返回的记录集
tableName in varchar2,–表名
Pagesize in number,–一页显示记录数
pageNow in number,–当前页
myrows out number,–总记录数
myPageCount out number–总页数
) is
–定义部分
–定义sql语句 字符串
v_sql varchar2(1000);
–定义两个整数
v_begin number:=(pageNow-1)*Pagesize+1;
v_end number:=pageNow*Pagesize;
begin
–执行部分
v_sql:=’select * from (select t1.*, rownum rn from (select * from ‘||tableName||’) t1 where rownum<=’||v_end||’) where rn>=’||v_begin;
–把游标和sql关联
open p_cursor for v_sql;
–计算myrows和myPageCount
–组织一个sql语句
v_sql:=’select count(*) from ‘||tableName;
–执行sql,并把返回的值,赋给myrows;
execute immediate v_sql into myrows;
–计算myPageCount
if mod(myrows,Pagesize)=0 then
myPageCount:=myrows/Pagesize;
else
myPageCount:=myrows/Pagesize+1;
end if;
end;
3.报表模板开发
A.参数定义:
B.数据集定义:
润乾报表可以使用存储过程作为数据集,一般情况下的输出参数类型均为“游标”类型,当然作为结果集返回一定 要使用游标类型。这里调用了分页存储过程fenye,查询结果返回为“游标”,传递给输出参数result。同时该存储过程还有3个输入参数,分别利用参数模板中定义的参数@p_table,@pageSize,@pageNo,输出参数除了有游标类型参数外还有非游标类型参数,参数返回结果分别传递给报表参数totalRows和PageCount。
C.单元格表达式:
为实现报表翻页功能,在报表第一行模拟翻页功能条的效果。注意这里的分页和存储过程中的分页是有区别的。这里的分页可以理解为逻辑分页,存储过程的分页可以理解为物理分页。一个物理分页的结果可以再划分为多个逻辑分页结果。这里的页码是逻辑分页的页码。
A1:
值表达式:=”共”+@totalRows+”条”
该单元格调用输出参数@totalRows返回结果,完成表达式拼接,显示总记录数。
B1:
值表达式:=”共”+@pageCount+”页”
该单元格调用输出参数@pageCount返回结果,完成表达式拼接,显示总页数。
C1:
值表达式:=”当前第”+int((@pageNo-1)*int(@pageSize/10)+pno())+”页”
该单元格利用参数@pageNo,@pageSize和当前页函数pno()得到当前访问页码(逻辑分页页码)。
D1:
值:上一页
可视表达式:if(@pageNo<=1,false,true) 如果当前物理分页小于等于1,不显示。
超链接表达式:=”/reportJsp/showReport.jsp?raq=pageProc.raq&pageNo=”+int(@pageNo-1)+”&pageSize=50″
刷新页面,存储过程查询上一个物理分页结果,返回给报表。(注意这里的存储过程分页大小(物理分页)为50)
F1:
值:上一页
可视表达式:if(@pageNo>=@pageCount,false,true) 如果当前物理分页大于等于总物理分页数,不显示。
超链接表达式:
=”/reportJsp/showReport.jsp?raq=pageProc.raq&pageNo=”+int(@pageNo+1)+”&pageSize=50″
刷新页面,存储过程查询下一个物理分页结果,返回给报表。(注意这里的存储过程分页大小(物理分页)为50)
E1:
值表达式:=to(1,@pageSize/10) 横向扩展,表示一个物理分页被分为了@pageSize/10个逻辑分页。
显示值表达式:=value()+(@pageNo-1)*int(@pageSize/10) 计算逻辑分页值
超链接表达式:=”javascript:report1_toPage(“+value()+”)” 调用内置功能函数完成指定页面跳转
4.效果展现:
性能对比
1).基于本文建立的测试数据表myTestTable(数据量20万),建立普通网格式报表。报表访问控制台打印信息如下,共用11秒。
如果测试数据上升至50万,报内存溢出错误,控制台输出信息如下:
2).基于本文建立的测试数据表myTestTable(数据量20万),建立行式报表。报表访问控制台打印信息如下,共用8秒。
如果测试数据上升至50万,报表展现速度缓慢,控制台输出信息如下,共用51秒。
3)用分页存储过程的方式,无论数据量是20万还是50万,报表访问展现速度都不会受到多大的影响,均能在1,2秒内完成报表展现。每次点击下一页的时候会根据参数调用存储过程进行数据查询。
小结
本文采用数据库存储过程+普通报表的方式,用普通html标签就可以完成大数据量报表的分页查询展现,不使用润乾提供的分页标签(extHtml和aotuBig标签)同样能实现大数据量报表的分页展现,提升报表展现速度。