數據的分頁是我們再熟悉不過的功能了,各種各樣的分頁方式層出不窮。今天我把一些常見的存儲過程分頁列出來,再簡單地測一下性能,算是對知識的總結,也是對您好想法的拋鑽引玉。廢話不多說,開始吧~~
1.首先建立一張測試表
--創建測試表 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[testTable]( [id] [int] IDENTITY(1,1) NOT NULL, [testDate] [datetime] NOT NULL CONSTRAINT [DF_testTable_testDate] DEFAULT (getdate()), [name] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL, [description] [nchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL, [orderColum] [float] NOT NULL, CONSTRAINT [PK_testTable] PRIMARY KEY CLUSTERED ( [id] ASC )WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY]
2.循環插入1000000條測試數據
declare @i int set @i = 1 while @i < 1000001 begin INSERT INTO testTable([name],[description],[orderColum]) VALUES('PageTest', 'http://www.3ymao.com', @i * rand()) set @i = @i + 1 end
3.曬出我的系統硬件和軟件(測試環境)
好吧,准備工作完成,開始進入主題(為了方便,以下代碼我就不寫成存儲過程的方式來測試展示了)~~噔噔!首先登場的是我最常用的Not IN
1)NOT IN
declare @timediff datetime declare @pageIndex int declare @pageSize int declare @sql varchar(500) set @pageIndex=1 set @pageSize=10 set @timediff=GetDATE() set @sql='select top ('+cast(@pageSize as varchar)+') * from testTable where (id not in ( select top '+cast(@pageSize*(@pageIndex-1) as varchar)+' id from testTable order by id)) order by id' exec(@sql) select datediff(ms,@timediff,Getdate())
@pageIndex=1時,運行:0ms(給力啊!)
@pageIndex=50000時,運行:346ms(怎么50000頁就不給力了)
@pageIndex=100000時,運行:326ms(怎么比50000頁時還少了?)
2)MAX()
declare @timediff datetime declare @pageIndex int declare @pageSize int declare @sql varchar(500) set @timediff=GetDATE() set @pageIndex=1 set @pageSize=10 set @sql='select top ('+cast(@pageSize as varchar)+') * from testTable where (id >= (select MAX(id) from (select top '+cast((@pageSize*(@pageIndex-1)+1) as varchar)+' id from testTable order by id) as a)) order by id' exec(@sql) select datediff(ms,@timediff,Getdate())
@pageIndex=1時,運行:0ms(也是很給力啊!)
@pageIndex=50000時,運行:123ms(不錯)
@pageIndex=100000時,運行:220ms(頁數和查詢時間成正比)
3)Row_Number()
declare @timediff datetime declare @pageIndex int declare @pageSize int declare @sql varchar(500) set @timediff=GetDATE() set @pageIndex=1 set @pageSize=10 set @sql='select * from (select *,row_number() over (order by id asc) as RowIndex from testTable) as IDWithRowNumber where RowIndex between '+cast(((@pageIndex-1)*@pageSize)+1 as varchar)+' and '+cast(@pageIndex*@pageSize as varchar)+'' exec(@sql) select datediff(ms,@timediff,getdate())
@pageIndex=1時,運行:0ms(好吧……數據量小的時候都是這尿性)
@pageIndex=50000時,運行:280ms(略遜色)
@pageIndex=100000時,運行:580ms(這貨居然也是頁數和查詢時間成正比!坑爹吧!)
4)臨時表
declare @timediff datetime declare @pageIndex int declare @pageSize int declare @sql varchar(500) declare @str varchar(500) set @timediff=GetDATE() set @pageIndex=1 set @pageSize=10 set @str='with tempTable as (select ceiling((Row_number() over (order by id asc))/'+cast(@pageSize as varchar)+') as page_num,* from testTable)' set @sql=@str+'select * from tempTable where page_num='+cast(@pageIndex-1 as varchar)+'' exec(@sql) select datediff(ms,@timediff,getdate())
@pageIndex=1時,運行:280ms(不咧個是吧!這非主流啊)
@pageIndex=50000時,運行:280ms(這不科學……)
@pageIndex=100000時,運行:280ms(好吧,這貨不受頁數的影響,永遠都這速度)
5)中間變量
declare @timediff datetime declare @pageIndex int declare @pageSize int declare @count int declare @id int declare @sql varchar(500) set @pageIndex=1 set @pageSize=10 select @id=0,@count=0,@timediff=GetDATE() select @count=@count+1,@id=case when @count=(@pageIndex-1)*@pageSize then id else @id end from testTable order by id set @sql='select top '+cast(@pageSize as varchar)+' * from testTable where id>'+cast(@id as varchar)+'' exec(@sql) select datediff(ms,@timediff,getdate())
@pageIndex=1時,運行:360ms(哥,不是吧,才第一頁你就這速度)
@pageIndex=50000時,運行:360ms(我大概猜到100000頁時的速度了……)
@pageIndex=100000時,運行:360ms(好吧,又是不受頁數影響的貨)
從以上數據,我最后簡單分析總結一下:
NOT IN:數據量小的時候,速度不錯,但是數據量大的時候速度就有點遜色了,但是好在隨着查詢頁數增大,他的速度還是不會改變多少。
MAX:小數據量的時候,它的速度是最快的,但是遺憾的是查詢頁數越大,速度則越慢。
Row_Number():性質與MAX相似,但是不比MAX速度快
臨時表:不會因為查詢頁數而改變查詢速度,只和數據量大小有關,個人覺得適合大數據量而且可能會查很大的頁數時使用
中間變量:性質和臨時表相似,但是遜色於臨時表