您的位置:首页 > 其它

分页实现方法的性能比较

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的指数,试验结果如下

页数TopNCTE临时表(有缓存)临时表(无缓存)

公司正在使用的存储过程CTE改进
1312101014577302
31577955244647191
1012755048838014646116
32588967212236019767602
1004680973816642354867151
31645271976432338675227255
1000Null980686925786358948
3162Null982224854110124608210
10000Null9754781211926142507359
31623Null97751872933218152497511
100000NullNull3153855569171396124
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: