0
点赞
收藏
分享

微信扫一扫

大数据量分页存储过程效率测试附代码


在项目中,我们经常遇到或用到分页,那么在大数据量(百万级以上)下,哪种分页算法效率最优呢?我们不妨用事实说话。

 

测试环境

硬件:CPU 酷睿双核T5750  内存:2G

软件:Windows server 2003    +   Sql server 2005

 

OK,我们首先创建一数据库:data_Test,并在此数据库中创建一表:tb_TestTable

 


 1

create

database
data_Test
--
创建数据库data_Test

2

GO

3

use
data_Test
4

GO

5

create

table
tb_TestTable
--
创建表

6

(
7

id
int

identity
(
1
,
1
)
primary

key
,
8

userName
nvarchar
(
20
)
not

null
,
9

userPWD
nvarchar
(
20
)
not

null
,
10

userEmail
nvarchar
(
40
)
null

11

)
12

GO

然后我们在数据表中插入2000000条数据:

1
-- 插入数据

2

set

identity_insert
tb_TestTable
on

3

declare

@count

int

4

set

@count
=
1

5

while

@count
<=
2000000

6

begin

7

insert

into
tb_TestTable(id,userName,userPWD,userEmail)
values
(
@count
,
'
admin
'
,
'
admin888
'
,
'
lli0077@yahoo.com.cn
'
)
8

set

@count
=
@count
+
1

9

end

10

set

identity_insert
tb_TestTable
off

我首先写了五个常用存储过程:
1,利用select top 和select not in进行分页,具体代码如下:


1
create procedure
proc_paged_with_notin
--
利用select top and select not in

2

(
3

@pageIndex
int
,
--
页索引

4


@pageSize

int

--
每页记录数

5

)
6

as

7

begin

8

set nocount
on
;
9

declare
@timediff

datetime

--
耗时

10


declare

@sql

nvarchar
(
500
)
11

select
@timediff
=
Getdate
()
12

set
@sql
=
'
select top
'
+
str
(
@pageSize
)
+
'
* from tb_TestTable where(ID not in(select top
'
+
str
(
@pageSize
*
@pageIndex
)
+
'
id from tb_TestTable order by ID ASC)) order by ID
'

13

execute (
@sql
)
--
因select top后不支技直接接参数,所以写成了字符串@sql

14


select

datediff
(ms,
@timediff
,
GetDate
())
as
耗时
15

set nocount
off
;
16

end

2,利用select top 和 select max(列键)


1 create procedure
proc_paged_with_selectMax
--
利用select top and select max(列)

2

(

3

@pageIndex int
,
--
页索引

4


@pageSize

int

--
页记录数

5

)
6

as

7

begin

8

set
nocount
on
;
9

declare @timediff

datetime

10

declare @sql

nvarchar
(
500
)
11

select @timediff
=
Getdate
()
12

set @sql
=
'
select top
'
+
str
(
@pageSize
)
+
'
* From tb_TestTable where(ID>(select max(id) From (select top
'
+
str
(
@pageSize
*
@pageIndex
)
+
'
id From tb_TestTable order by ID) as TempTable)) order by ID
'

13

execute ( @sql
)
14

select datediff
(ms,
@timediff
,
GetDate
())
as
耗时
15

set
nocount
off
;
16

end

3,利用select top和中间变量--此方法因网上有人说效果最佳,所以贴出来一同测试


1
create procedure proc_paged_with_Midvar --
利用ID>最大ID值和中间变量

2

(
3

@pageIndex int ,
4

@pageSize int
5

)
6

as

7

declare @count
int

8

declare @ID
int

9

declare @timediff
datetime

10

declare @sql
nvarchar
(
500
)
11

begin

12

set
nocount
on
;
13

select @count =
0
,
@ID
=
0
,
@timediff
=
getdate
()
14

select @count =
@count
+
1
,
@ID
=
case

when

@count
<=
@pageSize
*
@pageIndex

then
ID
else

@ID

end

from
tb_testTable
order

by
id
15

set @sql =
'
select top
'
+
str
(
@pageSize
)
+
'
* from tb_testTable where ID>
'
+
str
(
@ID
)
16

execute ( @sql )
17

select datediff (ms,
@timediff
,
getdate
())
as
耗时
18

set
nocount
off
;
19

end

20



4,利用Row_number() 此方法为SQL server 2005中新的方法,利用Row_number()给数据行加上索引



1
create procedure proc_paged_with_Rownumber -- 利用SQL 2005中的Row_number()

2

(
3

@pageIndex int ,
4

@pageSize int
5

)
6

as

7

declare @timediff datetime

8

begin

9

set
nocount
on
;
10

select @timediff = getdate
()
11

select * from
(
select

*
,Row_number()
over
(
order

by
ID
asc
)
as
IDRank
from
tb_testTable)
as
IDWithRowNumber
where
IDRank
>
@pageSize
*
@pageIndex

and
IDRank
<
@pageSize
*
(
@pageIndex
+
1
)
12

select datediff (ms, @timediff
,
getdate
())
as
耗时
13

set
nocount
off
;
14

end

15


5,利用临时表及Row_number


1
create procedure proc_CTE -- 利用临时表及Row_number
2

(
3

@pageIndex int , -- 页索引

4


@pageSize

int

--
页记录数

5

)
6

as

7

set nocount on ;
8

declare @ctestr nvarchar (
400
)
9

declare @strSql nvarchar (
400
)
10

declare @datediff datetime
11

begin

12

select @datediff = GetDate ()
13

set @ctestr = ' with Table_CTE as
14

(select ceiling((Row_number() over(order by ID ASC))/ ' + str ( @pageSize )
+
'
) as page_num,* from tb_TestTable)
'
;
15

set @strSql = @ctestr +
'
select * From Table_CTE where page_num=
'
+
str
(
@pageIndex
)
16

end

17

begin
18

execute sp_executesql @strSql
19

select datediff (ms, @datediff ,
GetDate
())
20

set nocount off ;
21

end
22



OK,至此,存储过程创建完毕,我们分别在每页10条数据的情况下在第2页,第1000页,第10000页,第100000页,第199999页进行测试,耗时单位:ms 每页测试5次取其平均值

存过
第2页耗时
第1000页耗时
第10000页耗时
第100000页耗时
第199999页耗时
效率排行
1用not in
0ms
16ms
47ms
475ms
953ms
3
2用select max
5ms
16ms
35ms
325ms
623ms
1
3中间变量
966ms
970ms
960ms
945ms
933ms
5
4row_number
0ms
0ms
34ms
365ms
710ms
2
4临时表
780ms
796ms
798ms
780ms
805ms
4

测试结果显示:select max >row_number>not in>临时表>中间变量

于是我对效率最高的select max方法用2分法进行了扩展,代码取自互联网,我修改了ASC排序时取不到值的BUG,测试结果:

2分法
156ms
156ms
180ms
470ms
156ms
1*


从测试结果来看,使用2分法确实可以提高效率并使效率更为稳定,我又增加了第159999页的测试,用时仅296ms,效果相当的不错!

下面是2分法使用select max的代码,已相当完善。


1
-- /*-----存储过程 分页处理 孙伟 2005-03-28创建 -------*/
2

-- /*-----存储过程 分页处理 浪尘 2008-9-1修改----------*/
3

-- /*----- 对数据进行了2分处理使查询前半部分数据与查询后半部分数据性能相同 -------*/
4


5

alter

PROCEDURE
proc_paged_2part_selectMax
6

(
7

@tblName

nvarchar
(
200
),
--
--要显示的表或多个表的连接

8

@fldName

nvarchar
(
500
)
=

'
*
'
,
--
--要显示的字段列表

9

@pageSize

int

=

10
,
--
--每页显示的记录个数

10

@page

int

=

1
,
--
--要显示那一页的记录

11

@fldSort

nvarchar
(
200
)
=

null
,
--
--排序字段列表或条件

12

@Sort

bit

=

0
,
--
--排序方法,0为升序,1为降序(如果是多字段排列Sort指代最后一个排序字段的排列顺序(最后一个排序字段不加排序标记)--程序传参如:' SortA Asc,SortB Desc,SortC ')

13

@strCondition

nvarchar
(
1000
)
=

null
,
--
--查询条件,不需where

14

@ID

nvarchar
(
150
),
--
--主表的主键

15

@Dist

bit

=

0
,
--
--是否添加查询字段的 DISTINCT 默认0不添加/1添加

16

@pageCount

int

=

1
output,
--
--查询结果分页后的总页数

17

@Counts

int

=

1
output
--
--查询到的记录数

18

)
19

AS

20

SET
NOCOUNT
ON

21

Declare

@sqlTmp

nvarchar
(
1000
)
--
--存放动态生成的SQL语句

22

Declare

@strTmp

nvarchar
(
1000
)
--
--存放取得查询结果总数的查询语句

23

Declare

@strID

nvarchar
(
1000
)
--
--存放取得查询开头或结尾ID的查询语句

24

举报

相关推荐

0 条评论