(问题解决再追加100分)sql server存储过程实现查询数据条数过大,分页查询怎么实现?
CREATEPROCEDURE[dbo].[sl_workbydaylog_hour]@begintimedatetime,--开始时间@endtimedatetime-...
CREATE PROCEDURE [dbo].[sl_workbydaylog_hour]
@begintime datetime,--开始时间
@endtime datetime --结束时间
AS
BEGIN
DECLARE @retucd int
DECLARE @erorcd char(2) --出错码
/* 初始化变量 */
SELECT @erorcd='99'
SELECT @erortx='未知错误'
create table #temp_5(
userid numeric(18, 0),--用户编号
startno varchar(10) COLLATE Chinese_PRC_CS_AI, --工作类型
gz_type varchar(10), --项目工作类型
prjtna varchar(200), --项目名
ctpdna varchar(200), --客户产品名称
ctpdno varchar(60) COLLATE Chinese_PRC_CS_AI, --客户产品
istrav varchar(20), --是否出差
addres varchar(100), --所在地
prjtcd varchar(60), --项目编号
contcd varchar(60), --合同编号
bgtime datetime, --开始时间
edtime datetime, --截止时间
cstate varchar(10), --审核状态
wdate datetime,
salesdept varchar(50), --售前支持申请起草人部门
workhour varchar(10) --工时
)
/* 获取工作周报数据, 仅项目拓展部*/
insert into #temp_5 (startno,gz_type,ctpdno,ctpdna,prjtcd,prjtna,istrav,addres,bgtime,edtime,cstate,userid,workhour,wdate)
select a.rstate ,a.gz_type, a.ctpdcd ,a.rz_c_proname ,a.ctpdcd ,a.rz_c_proname ,a.istrav ,a.rz_c_addr
,a.rz_c_bdate ,a.rz_c_bdate , a.cstate ,a.userid,a.rz_c_hour,a.ctdate
from sl_pm_daylog_content a
inner join pcmc_user u on a.userid=u.userid
--where a.rz_c_bdate>='2013-04-01' and a.rz_c_bdate<='2013-04-30' and b.rz_state=1 and u.deptid=92
where a.rz_c_bdate>=@begintime and a.rz_c_bdate<=@endtime
order by a.userid,a.rz_c_bdate
/*8.返回数据*/
select CONVERT(varchar(6),a.bgtime,112),(case when d.pdeptid=1 then d.deptname else d2.deptname end),
d.deptname,u.username,tp.rs_stana,tp2.parana,a.prjtna,a.ctpdna,
(case when a.istrav='0' then '否' else '是' end),
a.addres,a.prjtcd,a.contcd,a.bgtime,a.edtime,datediff(d,bgtime,edtime)+1,
(case when a.cstate='0' then '未审核' when a.cstate='1' then '已审核' else '不通过' end),
a.salesdept,a.wdate,a.workhour
from #temp_5 a
left join pcmc_user u on u.userid=a.userid
left join pcmc_dept d on d.deptid=u.deptid
left join pcmc_dept d2 on d2.deptid=d.pdeptid
left join sl_pm_daylog_nproject tp on tp.rs_state=a.startno
left join pcmc_knp_para tp2 on tp2.paratp='rz_type' and tp2.paracd=a.gz_type
这里返回结果5-8W左右,java后台要接收这些记录然后写入excel文件,但记录过多,内存溢出,或者性能差,现在如何实现分页查询,一批一批传到后台来写呢? 展开
@begintime datetime,--开始时间
@endtime datetime --结束时间
AS
BEGIN
DECLARE @retucd int
DECLARE @erorcd char(2) --出错码
/* 初始化变量 */
SELECT @erorcd='99'
SELECT @erortx='未知错误'
create table #temp_5(
userid numeric(18, 0),--用户编号
startno varchar(10) COLLATE Chinese_PRC_CS_AI, --工作类型
gz_type varchar(10), --项目工作类型
prjtna varchar(200), --项目名
ctpdna varchar(200), --客户产品名称
ctpdno varchar(60) COLLATE Chinese_PRC_CS_AI, --客户产品
istrav varchar(20), --是否出差
addres varchar(100), --所在地
prjtcd varchar(60), --项目编号
contcd varchar(60), --合同编号
bgtime datetime, --开始时间
edtime datetime, --截止时间
cstate varchar(10), --审核状态
wdate datetime,
salesdept varchar(50), --售前支持申请起草人部门
workhour varchar(10) --工时
)
/* 获取工作周报数据, 仅项目拓展部*/
insert into #temp_5 (startno,gz_type,ctpdno,ctpdna,prjtcd,prjtna,istrav,addres,bgtime,edtime,cstate,userid,workhour,wdate)
select a.rstate ,a.gz_type, a.ctpdcd ,a.rz_c_proname ,a.ctpdcd ,a.rz_c_proname ,a.istrav ,a.rz_c_addr
,a.rz_c_bdate ,a.rz_c_bdate , a.cstate ,a.userid,a.rz_c_hour,a.ctdate
from sl_pm_daylog_content a
inner join pcmc_user u on a.userid=u.userid
--where a.rz_c_bdate>='2013-04-01' and a.rz_c_bdate<='2013-04-30' and b.rz_state=1 and u.deptid=92
where a.rz_c_bdate>=@begintime and a.rz_c_bdate<=@endtime
order by a.userid,a.rz_c_bdate
/*8.返回数据*/
select CONVERT(varchar(6),a.bgtime,112),(case when d.pdeptid=1 then d.deptname else d2.deptname end),
d.deptname,u.username,tp.rs_stana,tp2.parana,a.prjtna,a.ctpdna,
(case when a.istrav='0' then '否' else '是' end),
a.addres,a.prjtcd,a.contcd,a.bgtime,a.edtime,datediff(d,bgtime,edtime)+1,
(case when a.cstate='0' then '未审核' when a.cstate='1' then '已审核' else '不通过' end),
a.salesdept,a.wdate,a.workhour
from #temp_5 a
left join pcmc_user u on u.userid=a.userid
left join pcmc_dept d on d.deptid=u.deptid
left join pcmc_dept d2 on d2.deptid=d.pdeptid
left join sl_pm_daylog_nproject tp on tp.rs_state=a.startno
left join pcmc_knp_para tp2 on tp2.paratp='rz_type' and tp2.paracd=a.gz_type
这里返回结果5-8W左右,java后台要接收这些记录然后写入excel文件,但记录过多,内存溢出,或者性能差,现在如何实现分页查询,一批一批传到后台来写呢? 展开
4个回答
展开全部
按说5-8w这样数量级的数据没有问题,写入Excel是布比较耗性能,主要还是要通过优化写入Excel的代码效率上去考虑。你可以考虑利用分批查询写入的方式来避免一次写太多的数据到Excel:将你的查询结果分段,比方你的语句中能不能用时间来认为分段,每次返回部分结果。
回到你的问题,对大数据量查询的解决方案有以下两种:
(1)、将全部数据先查询到内存中,然后在内存中进行分页,这种方式对内存占用较大,必须限制一次查询的数据量。
(2)、采用存储过程在数据库中进行分页,这种方式对数据库的依赖较大,不同的数据库实现机制不通,并且查询效率不够理想。以上两种方式对用户来说都不够友好。
2.解决思路
通过在待查询的数据库表上增加一个用于查询的自增长字段,然后采用该字段进行分页查询,可以很好地解决这个问题。下面举例说明这种分页查询方案。
(1)、在待查询的表格上增加一个long型的自增长列,取名为“queryId”,mssql、sybase直接支持自增长字段,oracle可以用sequence和trigger来实现。然后在该列上加上一个索引。
添加queryId列的语句如下:
Mssql: [QUERYID] [bigint] IDENTITY (1, 1)
Sybase: QUERYID numeric(19) identity
Oracle:
CREATE SEQUENCE queryId_S
INCREMENT BY 1
START WITH 1
MAXVALUE 999999999999999 MINVALUE 1
CYCLE
CACHE 20
ORDER;
CREATE OR REPLACE TRIGGER queryId_T BEFORE INSERT
ON "test_table"
FOR EACH ROW
BEGIN
select queryId_S.nextval into :new.queryId from dual;
END;
(2)、在查询第一页时,先按照大小顺序的倒序查出所有的queryId,
语句如下:select queryId from test_table where + 查询条件 +order by queryId desc 。
因为只是查询queryId字段,即使表格中的数据量很大,该查询也会很快得到结果。然后将得到的queryId保存在应用服务器的一个数组中。
(3)、用户在客户端进行翻页操作时,客户端将待查询的页号作为参数传递给应用服务器,服务器通过页号和queyId数组算出待查询的queyId最大和最小值,然后进行查询。
算出queyId最大和最小值的算法如下,其中page为待查询的页号,pageSize为每页的大小,queryIds为第二步生成的queryId数组:
int startRow = (page - 1) * pageSize
int endRow = page * pageSize - 1;
if (endRow >=queryIds.length)
{
endRow = this.queryIds.length - 1;
}
long startId =queryIds[startRow];
long endId =queryIds[endRow];
查询语句如下:
String sql = "select * from test_table" + 查询条件 + "(queryId <= " + startId + " and queryId >= " + endId + ")";
3.效果评价
该分页查询方法对所有数据库都适用,对应用服务器、数据库服务器、查询客户端的cpu和内存占用都较低,查询速度较快,是一个较为理想的分页查询实现方案。经过测试,查询4百万条数据,可以在3分钟内显示出首页数据,以后每一次翻页操作基本在2秒以内。内存和cpu占用无明显增长。
以上也仅仅是分页查询结果查看的问题,你需要写入到Excel的话还需要考虑Excel写入代码的执行效率,这部分是很值得研究的。
回到你的问题,对大数据量查询的解决方案有以下两种:
(1)、将全部数据先查询到内存中,然后在内存中进行分页,这种方式对内存占用较大,必须限制一次查询的数据量。
(2)、采用存储过程在数据库中进行分页,这种方式对数据库的依赖较大,不同的数据库实现机制不通,并且查询效率不够理想。以上两种方式对用户来说都不够友好。
2.解决思路
通过在待查询的数据库表上增加一个用于查询的自增长字段,然后采用该字段进行分页查询,可以很好地解决这个问题。下面举例说明这种分页查询方案。
(1)、在待查询的表格上增加一个long型的自增长列,取名为“queryId”,mssql、sybase直接支持自增长字段,oracle可以用sequence和trigger来实现。然后在该列上加上一个索引。
添加queryId列的语句如下:
Mssql: [QUERYID] [bigint] IDENTITY (1, 1)
Sybase: QUERYID numeric(19) identity
Oracle:
CREATE SEQUENCE queryId_S
INCREMENT BY 1
START WITH 1
MAXVALUE 999999999999999 MINVALUE 1
CYCLE
CACHE 20
ORDER;
CREATE OR REPLACE TRIGGER queryId_T BEFORE INSERT
ON "test_table"
FOR EACH ROW
BEGIN
select queryId_S.nextval into :new.queryId from dual;
END;
(2)、在查询第一页时,先按照大小顺序的倒序查出所有的queryId,
语句如下:select queryId from test_table where + 查询条件 +order by queryId desc 。
因为只是查询queryId字段,即使表格中的数据量很大,该查询也会很快得到结果。然后将得到的queryId保存在应用服务器的一个数组中。
(3)、用户在客户端进行翻页操作时,客户端将待查询的页号作为参数传递给应用服务器,服务器通过页号和queyId数组算出待查询的queyId最大和最小值,然后进行查询。
算出queyId最大和最小值的算法如下,其中page为待查询的页号,pageSize为每页的大小,queryIds为第二步生成的queryId数组:
int startRow = (page - 1) * pageSize
int endRow = page * pageSize - 1;
if (endRow >=queryIds.length)
{
endRow = this.queryIds.length - 1;
}
long startId =queryIds[startRow];
long endId =queryIds[endRow];
查询语句如下:
String sql = "select * from test_table" + 查询条件 + "(queryId <= " + startId + " and queryId >= " + endId + ")";
3.效果评价
该分页查询方法对所有数据库都适用,对应用服务器、数据库服务器、查询客户端的cpu和内存占用都较低,查询速度较快,是一个较为理想的分页查询实现方案。经过测试,查询4百万条数据,可以在3分钟内显示出首页数据,以后每一次翻页操作基本在2秒以内。内存和cpu占用无明显增长。
以上也仅仅是分页查询结果查看的问题,你需要写入到Excel的话还需要考虑Excel写入代码的执行效率,这部分是很值得研究的。
追问
你的方法是可以,但我这是做导出,不是做页面显示,页面显示的分页查已经有了,主要是导出时候分批查分批导,因为tomcat服务器性能一般,数据量大的话多用户同时页面导的时候容易挂,所以现在想优化这个存储过程,一次查改成分页分批查分批导!分还是给你吧,但追加就没了!要是你能帮我解决分批导的存储结构优化
请加Q2506820281 解决后给分300,要实力哦!
追答
还是我之前说明的,你的问题是在于需要优化写入Excel的代码。
展开全部
可采用row_number的方式来实现。
如表中数据如下:
id name
s1 张三
s3 李四
s5 王五
s7 赵六
s9 孙七
s11 杨八
如果要分页,只需要在查询中带上行号即可。
select id,name,row_number() over (order by id) rn from 表名
最后结果:
id name rn
s1 张三 1
s3 李四 2
s5 王五 3
s7 赵六 4
s9 孙七 5
s11 杨八 6
这样就完全满足了分页需求。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
分页呀,用RowNumber
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
用dataset取出数据,用linq分页
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询