使用SQL Server时,分页处理一直是个比较棘手的问题
正常情况下,SQL Server服务器上会对使用频率大的Table建立合适的索引
这样能大幅度的提高数据库本身的数据检索速度,建立索引的方法就不细说了
如果需要返回大量数据,从几百行到几万行,甚至几十万行数据
这时会发现响应速度越来越慢,甚至发生响应超时的错误
为了解决这种大数据量请求的问题,就不得不使用分页模式了
在这方面,JDBC就强悍得多,它可以将指定的行数和SQL请求一并发送给SQL Server,这样只返回分页后的数据,JDBC的原理还不清楚,但在实际使用中,速度还是非常快的
如果没办法使用JDBC,最常用的方法就是存储过程了!
我在写这个分页存储之前,参考了网上的大量相关文章,可以通过关键字:SQL Server 分页 进行搜索
他们主要都是利用SQL中的Top方法,并且对所检索的数据结构要求有标识列,如果没有标识列,或者是联合主键,那么就会非常麻烦了。而且对应用里原有的SQL检索部分需要修改的地方较多,工作量较大。
因此,我在写这个存储之前就要求一定要对原有的SQL脚本最大程度的兼容
经过一个下午的时间,和我一个同事(绝对是高手)的共同努力下,摸索出了以下的思路:
1、确定存储的输入参数:
1)SQL脚本,该参数接收完整的、正确的SQL检索文本,可将原应用中写好的SQL脚本直接传入
2)每页的数据容量,就是一页有多少条数据
3)当前页码
2、确定分页机制:
1)执行传入的SQL脚本,并将结果生成临时表
2)修改临时表的结构,增加标识列字段
3)根据标识列字段,计算出指定页码内的记录范围,并返回
4)返回总数据条数,用于客户端进行分页显示
根据以上的思路,编写出以下通用的分页存储过程:
1
--
// ============================
2 -- // SQL Server通用分页存储过程
3 -- // Author : netwild
4 -- // date : 2010/07/22
5 -- // Email : netwild@163.com
6 -- // QQ : 52100641(网无忌)
7 -- // ============================
8
9 SET QUOTED_IDENTIFIER ON
10 GO
11 SET ANSI_NULLS ON
12 GO
13
14
15 CREATE PROC execByPage
16
17 @sqlQuery varchar ( 2000 ), -- //输入参数:SQL检索语句或表名
18 @pageSize int , -- //输入参数:每页显示记录条数
19 @pageIndex int -- //输入参数:当前页码
20
21 AS
22
23 SET NOCOUNT ON
24 SET ANSI_WARNINGS OFF
25
26 declare @tmpTableName varchar ( 50 )
27 set @tmpTableName = ' ##TB1516_ ' + replace ( cast ( newid () as varchar ( 40 )), ' - ' , '' ) -- //生成随机临时表名称
28
29 declare @subIndex int
30 set @subIndex = charindex ( ' from ' , @sqlQuery )
31 if ( @subIndex > 0 )
32 begin -- //带FROM的标准检索语句
33 declare @sqlQuery1 varchar ( 2000 )
34 declare @sqlQuery2 varchar ( 2000 )
35 set @sqlQuery1 = substring ( @sqlQuery , 1 , @subIndex - 1 )
36 set @sqlQuery2 = substring ( @sqlQuery , @subIndex , len ( @sqlQuery ))
37 set @sqlQuery = @sqlQuery1 + ' ,IDENTITY(numeric,1,1) as ID1516 into ' + @tmpTableName + ' ' + @sqlQuery2
38 end
39 else -- //不带FROM的表名
40 begin
41 set @sqlQuery = ' select *,IDENTITY(numeric,1,1) as ID1516 into ' + @tmpTableName + ' from ' + @sqlQuery
42 end
43 exec ( @sqlQuery ) -- //建立并初始化临时表数据
44
45 declare @indexStart varchar ( 20 ), @indexEnd varchar ( 20 )
46 set @indexStart = cast (( @pageIndex - 1 ) * @pageSize + 1 as varchar ( 20 )) -- //数据起始行ID
47 set @indexEnd = cast ( @pageIndex * @pageSize as varchar ( 20 )) -- //数据结束行ID
48
49 exec ( ' select * from ' + @tmpTableName + ' where ID1516 between ' + @indexStart + ' and ' + @indexEnd ) -- //检索该页数据
50
51 exec ( ' select max(ID1516) as recordCount from ' + @tmpTableName ) -- //提取总条数
52
53 exec ( ' drop table ' + @tmpTableName ) -- //删除临时表
54
55
56 GO
57 SET QUOTED_IDENTIFIER OFF
58 GO
59 SET ANSI_NULLS ON
60 GO
2 -- // SQL Server通用分页存储过程
3 -- // Author : netwild
4 -- // date : 2010/07/22
5 -- // Email : netwild@163.com
6 -- // QQ : 52100641(网无忌)
7 -- // ============================
8
9 SET QUOTED_IDENTIFIER ON
10 GO
11 SET ANSI_NULLS ON
12 GO
13
14
15 CREATE PROC execByPage
16
17 @sqlQuery varchar ( 2000 ), -- //输入参数:SQL检索语句或表名
18 @pageSize int , -- //输入参数:每页显示记录条数
19 @pageIndex int -- //输入参数:当前页码
20
21 AS
22
23 SET NOCOUNT ON
24 SET ANSI_WARNINGS OFF
25
26 declare @tmpTableName varchar ( 50 )
27 set @tmpTableName = ' ##TB1516_ ' + replace ( cast ( newid () as varchar ( 40 )), ' - ' , '' ) -- //生成随机临时表名称
28
29 declare @subIndex int
30 set @subIndex = charindex ( ' from ' , @sqlQuery )
31 if ( @subIndex > 0 )
32 begin -- //带FROM的标准检索语句
33 declare @sqlQuery1 varchar ( 2000 )
34 declare @sqlQuery2 varchar ( 2000 )
35 set @sqlQuery1 = substring ( @sqlQuery , 1 , @subIndex - 1 )
36 set @sqlQuery2 = substring ( @sqlQuery , @subIndex , len ( @sqlQuery ))
37 set @sqlQuery = @sqlQuery1 + ' ,IDENTITY(numeric,1,1) as ID1516 into ' + @tmpTableName + ' ' + @sqlQuery2
38 end
39 else -- //不带FROM的表名
40 begin
41 set @sqlQuery = ' select *,IDENTITY(numeric,1,1) as ID1516 into ' + @tmpTableName + ' from ' + @sqlQuery
42 end
43 exec ( @sqlQuery ) -- //建立并初始化临时表数据
44
45 declare @indexStart varchar ( 20 ), @indexEnd varchar ( 20 )
46 set @indexStart = cast (( @pageIndex - 1 ) * @pageSize + 1 as varchar ( 20 )) -- //数据起始行ID
47 set @indexEnd = cast ( @pageIndex * @pageSize as varchar ( 20 )) -- //数据结束行ID
48
49 exec ( ' select * from ' + @tmpTableName + ' where ID1516 between ' + @indexStart + ' and ' + @indexEnd ) -- //检索该页数据
50
51 exec ( ' select max(ID1516) as recordCount from ' + @tmpTableName ) -- //提取总条数
52
53 exec ( ' drop table ' + @tmpTableName ) -- //删除临时表
54
55
56 GO
57 SET QUOTED_IDENTIFIER OFF
58 GO
59 SET ANSI_NULLS ON
60 GO
宠辱不惊,看庭前花开花落;去留无意,望天上云卷云舒