分页实现方法的性能比较
2009-05-12 10:47
459 查看
我们先给出几种主要的分页方法和核心语句,然后直接给出结论,有兴趣的读者可以看看后面的数据
几种常用存储过程分页方法
TopN方法
select Top(@PageSize) from TableName where ID Not IN
(Select Top ((@PageIndex-1)*@PageSize) ID from Table Name where .... order by ... )
where .... order by ...
临时表
declare @indextable table(id int identity(1,1),nid int,PostUserName nvarchar(50))
declare @PageLowerBound int
declare @PageUpperBound int
set @PageLowerBound=(@pageindex-1)*@pagesize--下限
set @PageUpperBound=@PageLowerBound+@pagesize--上限
set rowcount @PageUpperBound
insert into @indextable(nid,PostUserName) select ReplyID,PostUserName from TableName order by ......
select * from TableName p,@indextable t where p.ID=t.nid
and t.id>@PageLowerBound and t.id<=@PageUpperBound order by t.id
CTE--2005新语法,类似临时表,但是生命周期稍微不同,这里只是他的一个运用
with cte_temp--定义零时表,PageIndex是一个计算字段,储存了搜索结果的页号
As (ceiling((Row_Number() over(order by .... )-1)/@pagesize as int) as PageIndex,* from TableName where.....)
select * from cte_temp where pageindex=@pageindex-1;
结论:
TopN在小页数下最快,如果在10页以下,可以考虑用它,CTE和临时表时间很稳定,CTE消耗的时间比临时表多,但是不会引起tempdb的暴涨和IO增加
性能比较
试验环境:win2003server,Sqlserver2005,库大小2,567,245行,没有where子句,试验时每页大小50,页码作为变量
取0,3,10,31,100,316,1000,3162...页,也就是10的指数,试验结果如下
SET ANSI_NULLS ON
2GO
3SET QUOTED_IDENTIFIER ON
4GO
5CREATE TABLE [dbo].[testTable](
6 [id] [int] IDENTITY(1,1) NOT NULL,
7 [testDate] [datetime] NOT NULL CONSTRAINT [DF_testTable_testDate] DEFAULT (getdate()),
8 [name] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
9 [description] [nchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
10 [orderColum] [float] NOT NULL,
11 CONSTRAINT [PK_testTable] PRIMARY KEY CLUSTERED
12(
13 [id] ASC
14)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
15) ON [PRIMARY]
16
填充一下表,加了3W条记录,倒是不多。
1declare @i int
2 set @i = 1
3 while @i < 30001
4 begin
5 INSERT INTO testTable([name],[description],[orderColum])
6 VALUES('names', 'descriiption', @i * rand())
7 set @i = @i +1
8 end
1、TopN方法:这个方法就不多说了,相当普遍,页码少的时候比较好使。
[代码]
1=============================================
2-- Author: <Author,,microant>
3-- Create date: <2007年7月5日,,>
4-- Description: <Description,selectTopN分页方法,>
5-- =============================================
6CREATE PROCEDURE [dbo].[sp_SelectTopN](
7 -- Add the parameters for the stored procedure here
8 @TableName varchar(200) = 'testTable', --表名
9 @PageSize int = 15, --页面大小
10 @PageIndex int =2 , --页面的序号
11 --@IsCountNull bit =1, --返回记录是否为空
12 @IsAsc bit = 1 , --是否卫升序,升序为1,降序为0
13 @OderColumName varchar(200) = null, --排序字段名
14 @KeyID varchar(50) = 'id', --主键
15 @Conditions varchar(500) = null --查询条件
16)
17AS
18 set nocount on
19
20 declare @strSql nvarchar(1000)
21 declare @tempstr nvarchar(1000)
22 declare @orderstr nvarchar(400)
23
24--判断排序方式,@IsAsc =1 升序, 0降序,设置排序语句
25 if @IsAsc = 1
26 begin
27 if(@OderColumName is null or @OderColumName = '')
28 set @orderstr = ' order by ' + @KeyID + ' asc'
29 else
30 set @orderstr = ' order by ' + @OderColumName + ' asc'
31 end
32 else
33 begin
34 if(@OderColumName is null or @OderColumName = '')
35 set @orderstr = ' order by ' + @KeyID + ' desc'
36 else
37 set @orderstr = ' order by ' + @OderColumName + ' desc'
38 end
39
40--查询条件是否添加
41 if @Conditions is null
42 begin
43 set @tempstr = 'select top ' + str(@PageSize*@PageIndex) +' ' +@KeyID +' from ' + @TableName + @orderstr;
44 set @strSql = 'select top ' + str(@PageSize)+ ' * from ' + @TableName + ' where ' + @KeyID +' not in ( ' + @tempstr +')' + @orderstr;
45 end
46 else
47 begin
48 set @tempstr = 'select top ' + str(@PageSize*@PageIndex) +' ' +@KeyID +' from ' + @TableName+ ' where ' + @Conditions + ' ' + @orderstr;
49 set @strSql = 'select top ' + str(@PageSize)+ ' * from ' + @TableName + ' where ' + @Conditions + ' and ' + @KeyID +' not in (' + @tempstr +')' + @orderstr;
50 end
51 print @strSql
52 exec sp_executesql @strSql
53set nocount off
54
[测试]
1DECLARE @return_value int
2EXEC @return_value = [dbo].[sp_SelectTopN]
3 @TableName = N'testTable',
4 @PageSize = 30,
5 @PageIndex = 4,
6 @IsAsc = 0,
7 @OderColumName = N'orderColum',
8 @KeyID = N'id',
9 @Conditions = 'id > 50'
10SELECT 'Return Value' = @return_value
11go
12
2、CTE方法:
CTE(常见表表达式)是一个可以由定义语句引用的临时命名的结果集,和临时表比较相似。一般形式如下,
WITH <cte_alias>(<column_aliases>)
AS
(
<cte_query>
)
SELECT *
FROM <cte_alias>
但是比临时表慢,但是考虑临时表会增大日志文件的大小,引起大量IO,CTE也就有他自己的优势。性能分析详情参见http://blog.csdn.net/yizhu2000/archive/2007/06/03/1636573.aspx
[代码]
1-- =============================================
2-- Author: <Author,,microant>
3-- Create date: <Create Date,,20070705>
4-- Description: <Description,,CTE分页>
5-- =============================================
6CREATE PROCEDURE [dbo].[sp_CTE](
7 -- Add the parameters for the stored procedure here
8 @TableName varchar(200) = 'testTable', --表名
9 @PageSize int = 15, --页面大小
10 @PageIndex int =2 , --页面的序号
11 --@IsCountNull bit =1, --返回记录是否为空
12 @IsAsc bit = 1 , --是否卫升序,升序为1,降序为0
13 @OderColumName varchar(200) = null, --排序字段名
14 @KeyID varchar(50) = 'id', --主键
15 @Conditions varchar(500) = null --查询条件
16)
17AS
18
19 -- SET NOCOUNT ON added to prevent extra result sets from
20 -- interfering with SELECT statements.
21 SET NOCOUNT ON;
22
23 declare @strSql nvarchar(1000)
24 declare @tempstr nvarchar(1000)
25 declare @orderstr nvarchar(400)
26 declare @ctestr nvarchar(400)
27
28 --判断排序方式,@IsAsc =1 升序, 0降序,设置排序语句
29 if @IsAsc = 1
30 begin
31 if(@OderColumName is null or @OderColumName = '')
32 set @orderstr = ' order by ' + @KeyID + ' asc'
33 else
34 set @orderstr = ' order by ' + @OderColumName + ' asc'
35 end
36 else
37 begin
38 if(@OderColumName is null or @OderColumName = '')
39 set @orderstr = ' order by ' + @KeyID + ' desc'
40 else
41 set @orderstr = ' order by ' + @OderColumName + ' desc'
42 end
43
44 --CTE
45 set @ctestr ='with Table_CET
46 as
47 (
48 select
49 CEILING((ROW_NUMBER() OVER (' + @orderstr + '))/' + str(@PageSize) + ') as page_num, *
50 from ' + @TableName +
51 ')' ;
52
53
54 set @strSql = @ctestr + 'select * from Table_CET where page_num = ' + str(@PageIndex)+ ' and ' + @Conditions;
55
56 print @strSql
57 begin
58 exec sp_executesql @strSql;
59 end
[测试]
1DECLARE @return_value int
2EXEC @return_value = [dbo].[sp_CTE]
3 @TableName = N'testTable',
4 @PageSize = 30,
5 @PageIndex = 4,
6 @IsAsc = 0,
7 @OderColumName = N'orderColum',
8 @KeyID = N'id',
9 @Conditions = 'id > 50'
10SELECT 'Return Value' = @return_value
11GO
3、以前没太关注SQL server 2005的新功能,一直在用MySQL,或者2000,每天关注Oracle但是很不幸都没机会做过什么。不曾想加了不少共能,得好好看看。师兄再给我说他们在用Informax等一系列工具做数据仓库,很高兴听到几个不懂得名词,很不幸没有机会见识见识。还是务实点看看2005提供了啥吧。
T-SQL也出现了不少新功,CTE就不错看着,比较好使,具体参见https://www.microsoft.com/china/msdn/library/data/sqlserver/05TSQLEnhance.mspx?mfr=true
几种常用存储过程分页方法
TopN方法
select Top(@PageSize) from TableName where ID Not IN
(Select Top ((@PageIndex-1)*@PageSize) ID from Table Name where .... order by ... )
where .... order by ...
临时表
declare @indextable table(id int identity(1,1),nid int,PostUserName nvarchar(50))
declare @PageLowerBound int
declare @PageUpperBound int
set @PageLowerBound=(@pageindex-1)*@pagesize--下限
set @PageUpperBound=@PageLowerBound+@pagesize--上限
set rowcount @PageUpperBound
insert into @indextable(nid,PostUserName) select ReplyID,PostUserName from TableName order by ......
select * from TableName p,@indextable t where p.ID=t.nid
and t.id>@PageLowerBound and t.id<=@PageUpperBound order by t.id
CTE--2005新语法,类似临时表,但是生命周期稍微不同,这里只是他的一个运用
with cte_temp--定义零时表,PageIndex是一个计算字段,储存了搜索结果的页号
As (ceiling((Row_Number() over(order by .... )-1)/@pagesize as int) as PageIndex,* from TableName where.....)
select * from cte_temp where pageindex=@pageindex-1;
结论:
TopN在小页数下最快,如果在10页以下,可以考虑用它,CTE和临时表时间很稳定,CTE消耗的时间比临时表多,但是不会引起tempdb的暴涨和IO增加
性能比较
试验环境:win2003server,Sqlserver2005,库大小2,567,245行,没有where子句,试验时每页大小50,页码作为变量
取0,3,10,31,100,316,1000,3162...页,也就是10的指数,试验结果如下
页数 | TopN | CTE | 临时表(有缓存) | 临时表(无缓存) | 公司正在使用的存储过程 | CTE改进 |
1 | 3 | 12 | 10 | 101 | 457 | 7302 |
3 | 15 | 7 | 79 | 5524 | 464 | 7191 |
10 | 127 | 5504 | 88 | 3801 | 464 | 6116 |
32 | 588 | 9672 | 122 | 3601 | 976 | 7602 |
100 | 4680 | 9738 | 166 | 4235 | 486 | 7151 |
316 | 45271 | 9764 | 323 | 3867 | 522 | 7255 |
1000 | Null | 9806 | 869 | 2578 | 635 | 8948 |
3162 | Null | 9822 | 2485 | 4110 | 12460 | 8210 |
10000 | Null | 9754 | 7812 | 11926 | 14250 | 7359 |
31623 | Null | 9775 | 18729 | 33218 | 15249 | 7511 |
100000 | Null | Null | 31538 | 55569 | 17139 | 6124 |
2GO
3SET QUOTED_IDENTIFIER ON
4GO
5CREATE TABLE [dbo].[testTable](
6 [id] [int] IDENTITY(1,1) NOT NULL,
7 [testDate] [datetime] NOT NULL CONSTRAINT [DF_testTable_testDate] DEFAULT (getdate()),
8 [name] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
9 [description] [nchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
10 [orderColum] [float] NOT NULL,
11 CONSTRAINT [PK_testTable] PRIMARY KEY CLUSTERED
12(
13 [id] ASC
14)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
15) ON [PRIMARY]
16
填充一下表,加了3W条记录,倒是不多。
1declare @i int
2 set @i = 1
3 while @i < 30001
4 begin
5 INSERT INTO testTable([name],[description],[orderColum])
6 VALUES('names', 'descriiption', @i * rand())
7 set @i = @i +1
8 end
1、TopN方法:这个方法就不多说了,相当普遍,页码少的时候比较好使。
[代码]
1=============================================
2-- Author: <Author,,microant>
3-- Create date: <2007年7月5日,,>
4-- Description: <Description,selectTopN分页方法,>
5-- =============================================
6CREATE PROCEDURE [dbo].[sp_SelectTopN](
7 -- Add the parameters for the stored procedure here
8 @TableName varchar(200) = 'testTable', --表名
9 @PageSize int = 15, --页面大小
10 @PageIndex int =2 , --页面的序号
11 --@IsCountNull bit =1, --返回记录是否为空
12 @IsAsc bit = 1 , --是否卫升序,升序为1,降序为0
13 @OderColumName varchar(200) = null, --排序字段名
14 @KeyID varchar(50) = 'id', --主键
15 @Conditions varchar(500) = null --查询条件
16)
17AS
18 set nocount on
19
20 declare @strSql nvarchar(1000)
21 declare @tempstr nvarchar(1000)
22 declare @orderstr nvarchar(400)
23
24--判断排序方式,@IsAsc =1 升序, 0降序,设置排序语句
25 if @IsAsc = 1
26 begin
27 if(@OderColumName is null or @OderColumName = '')
28 set @orderstr = ' order by ' + @KeyID + ' asc'
29 else
30 set @orderstr = ' order by ' + @OderColumName + ' asc'
31 end
32 else
33 begin
34 if(@OderColumName is null or @OderColumName = '')
35 set @orderstr = ' order by ' + @KeyID + ' desc'
36 else
37 set @orderstr = ' order by ' + @OderColumName + ' desc'
38 end
39
40--查询条件是否添加
41 if @Conditions is null
42 begin
43 set @tempstr = 'select top ' + str(@PageSize*@PageIndex) +' ' +@KeyID +' from ' + @TableName + @orderstr;
44 set @strSql = 'select top ' + str(@PageSize)+ ' * from ' + @TableName + ' where ' + @KeyID +' not in ( ' + @tempstr +')' + @orderstr;
45 end
46 else
47 begin
48 set @tempstr = 'select top ' + str(@PageSize*@PageIndex) +' ' +@KeyID +' from ' + @TableName+ ' where ' + @Conditions + ' ' + @orderstr;
49 set @strSql = 'select top ' + str(@PageSize)+ ' * from ' + @TableName + ' where ' + @Conditions + ' and ' + @KeyID +' not in (' + @tempstr +')' + @orderstr;
50 end
51 print @strSql
52 exec sp_executesql @strSql
53set nocount off
54
[测试]
1DECLARE @return_value int
2EXEC @return_value = [dbo].[sp_SelectTopN]
3 @TableName = N'testTable',
4 @PageSize = 30,
5 @PageIndex = 4,
6 @IsAsc = 0,
7 @OderColumName = N'orderColum',
8 @KeyID = N'id',
9 @Conditions = 'id > 50'
10SELECT 'Return Value' = @return_value
11go
12
2、CTE方法:
CTE(常见表表达式)是一个可以由定义语句引用的临时命名的结果集,和临时表比较相似。一般形式如下,
WITH <cte_alias>(<column_aliases>)
AS
(
<cte_query>
)
SELECT *
FROM <cte_alias>
但是比临时表慢,但是考虑临时表会增大日志文件的大小,引起大量IO,CTE也就有他自己的优势。性能分析详情参见http://blog.csdn.net/yizhu2000/archive/2007/06/03/1636573.aspx
[代码]
1-- =============================================
2-- Author: <Author,,microant>
3-- Create date: <Create Date,,20070705>
4-- Description: <Description,,CTE分页>
5-- =============================================
6CREATE PROCEDURE [dbo].[sp_CTE](
7 -- Add the parameters for the stored procedure here
8 @TableName varchar(200) = 'testTable', --表名
9 @PageSize int = 15, --页面大小
10 @PageIndex int =2 , --页面的序号
11 --@IsCountNull bit =1, --返回记录是否为空
12 @IsAsc bit = 1 , --是否卫升序,升序为1,降序为0
13 @OderColumName varchar(200) = null, --排序字段名
14 @KeyID varchar(50) = 'id', --主键
15 @Conditions varchar(500) = null --查询条件
16)
17AS
18
19 -- SET NOCOUNT ON added to prevent extra result sets from
20 -- interfering with SELECT statements.
21 SET NOCOUNT ON;
22
23 declare @strSql nvarchar(1000)
24 declare @tempstr nvarchar(1000)
25 declare @orderstr nvarchar(400)
26 declare @ctestr nvarchar(400)
27
28 --判断排序方式,@IsAsc =1 升序, 0降序,设置排序语句
29 if @IsAsc = 1
30 begin
31 if(@OderColumName is null or @OderColumName = '')
32 set @orderstr = ' order by ' + @KeyID + ' asc'
33 else
34 set @orderstr = ' order by ' + @OderColumName + ' asc'
35 end
36 else
37 begin
38 if(@OderColumName is null or @OderColumName = '')
39 set @orderstr = ' order by ' + @KeyID + ' desc'
40 else
41 set @orderstr = ' order by ' + @OderColumName + ' desc'
42 end
43
44 --CTE
45 set @ctestr ='with Table_CET
46 as
47 (
48 select
49 CEILING((ROW_NUMBER() OVER (' + @orderstr + '))/' + str(@PageSize) + ') as page_num, *
50 from ' + @TableName +
51 ')' ;
52
53
54 set @strSql = @ctestr + 'select * from Table_CET where page_num = ' + str(@PageIndex)+ ' and ' + @Conditions;
55
56 print @strSql
57 begin
58 exec sp_executesql @strSql;
59 end
[测试]
1DECLARE @return_value int
2EXEC @return_value = [dbo].[sp_CTE]
3 @TableName = N'testTable',
4 @PageSize = 30,
5 @PageIndex = 4,
6 @IsAsc = 0,
7 @OderColumName = N'orderColum',
8 @KeyID = N'id',
9 @Conditions = 'id > 50'
10SELECT 'Return Value' = @return_value
11GO
3、以前没太关注SQL server 2005的新功能,一直在用MySQL,或者2000,每天关注Oracle但是很不幸都没机会做过什么。不曾想加了不少共能,得好好看看。师兄再给我说他们在用Informax等一系列工具做数据仓库,很高兴听到几个不懂得名词,很不幸没有机会见识见识。还是务实点看看2005提供了啥吧。
T-SQL也出现了不少新功,CTE就不错看着,比较好使,具体参见https://www.microsoft.com/china/msdn/library/data/sqlserver/05TSQLEnhance.mspx?mfr=true
相关文章推荐
- 分页实现方法的性能比较
- 分页实现方法的性能比较
- 分页实现方法的性能比较
- 分页实现方法的性能比较
- ASP.NET数据分页的多种实现方法及性能比较
- 分页实现方法的性能比较
- 常用存储过程分页实现方法的性能比较
- [转]分页实现方法的性能比较
- 分页实现方法的性能比较
- 分页实现方法的性能比较
- 分页实现方法的性能比较
- ibatis默认实现分页与Oracle SQL分页性能比较
- (转)判断一个字符串是否全是数字的多种方法及其性能比较(C#实现
- 数组排序方法的性能比较(3):LINQ排序实现分析
- 判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)--来源CSDN
- 不同梯度下降方法实现逻辑回归性能比较(python)
- 一起谈.NET技术,数组排序方法的性能比较(中):Array.Sort<T> 实现分析
- 判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)
- 判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)
- 并查集类的c++封装,比较union_find algorithm四种实现方法之间的性能差别