SQL Server 2005用Row_Number分頁

1、爲什麼要使用row方案:
在oracle裏有row_number虛列,
mySql有limit關鍵字分頁,
他們都有一個比較通用的分頁方案,
使得hibernate等類似的程序可以拼接sql字符串提供通用的分頁。
而sqlserver卻沒有這樣的分頁方案。
於是乎,本人稍稍改裝row_number()over(order by )用法,獲得了一個通用的分頁方案。
如提供了sql如下:

select * from Student where Age>18 order by Age

被row方案的分頁程序處理後變成
(在select 後面添加 top 開始位置 0 __tc,在外層嵌套固定模式的查詢sql)

select  * 
from (
select row_number()over(orderby __tc__)__rn__,*
from (selecttop 開始位置+100 __tc__,*from Student where Age>18 order by Age)t
)tt
where __rn__>開始位置


這樣就得到了拼接出通用的分頁sql方案了。
並且經過本人測試發現,這套方案的運行速度不遜於任何一套其他方案。
其餘各方面效率還有待考察,忘高人指點了。

2、row方案的排序:
row方案可以任意排序,
只要修改最內層的select排序即可,
應該來說是很簡單易用的。
參考【追加說明1、】和【#80樓】。

3、row方案和普通row_number()方案的區別:

一般的row方案:

select * 
from (select top 開始位置+10 row_number() over(order by Id)__rn__, * from Student)t
where __rn__>=開始的位置


使用了over(order by 表中的列),照成了必須由用戶提供這個列,
而不容易使用分頁程序生成分頁sql(如hibernate分頁)。
而row方案使用的是一個常數列tempColumn,值永遠是0。

select * 
from (
select row_number() over(order by TempColmun) *
from (
select top 開始的位置 0 as TempColmun,*
from Student order by Id
)tt)t
where rowNumber >=開始的位置


這個列是靜態的,只是爲了使用row_number()函數,
並不是真正的order by 依據,order by 實際看最內層。

我分析是因爲row方案使用一個靜態的列tempColumn,
這樣可能被sql分析程序認爲是無需排序的,省下了排序過程的開銷。

4、數據測試:
現只在我一臺機子上試過,
希望路過的各位隨手幫忙測試一下。
這也是我遲遲不結貼的緣故。

舉手之勞,複製sql運行即可:

--插入測試數據200w條,可能會很久
create table Student(
Id int PRIMARYKEY identity(1,1),
Name nvarchar(50),
Age int)
insert Student(Name,Age)values('Name',18)
while (select count(*) from Student)<2000000
insert Student select Name,Age from Student



運行測試代碼:

--開始測試查詢
declare @now datetime
--max方案
select 'max' 方案
select @now=getdate()
--begin
select top 10 * from Student
where Id>(
select max(Id)
from (
select top 1999990 Id from Student order by Id)tt)
--end
declare @maxDiff int
select maxDiff=datediff(ms,@now,getdate())

--top方案
select 'top' 方案
select @now=getdate()
--begin
select top 10 * from Student
where Id not in(select top 1999990 Id from Student)
--end
declare @topDiff int
select @topDiff=datediff(ms,@now,getdate())

--row方案
select 'row' 方案
select @now=getdate()
--begin
select *
from (
select row_number()over(orderby tc)rn,*
from (select top 20000000 tc,* from Student)t
)tt
where rn>1999990
--end
declare @rowDiff int
select @rowDiff=datediff(ms,@now,getdate())

--row_number方案
select 'row_number' 方案
select @now=getdate()
--begin
select *
from(
select top2000000 row_number() over(order by Id)rn,* from Student
)t
where rn>1999990
--end
declare @row_numberDiff int
select @row_numberDiff=datediff(ms,@now,getdate())

--記錄結果
select '第20萬頁' 頁碼,@maxDiff max方案,@topDiff top方案,@rowDiff row方案,@row_numberDiff row_number方案


-----------------------------------------------------------
以下爲原帖:
-----------------------------------------------------------
這套方案(下面簡稱row方案)是本人借鑑Oracle的row_number分頁方法和sqlServerrow_number結合+上top分頁方案合體版,經過本人初步測試。
效率非常快。(本人測試非常業餘,還望高人幫忙測試。)
row方案的具體操作方法在這章帖子裏:
一套原創的sqlserver通用分頁方案 忘高人測試效率 先阿里嘎多了

比較了3種分頁方式,分別是max方案,top方案,row方案

效率:
  第1:row
  第2:max
  第3:top

缺點:
  max:必須用戶編寫複雜Sql,不支持非唯一列排序
  top:必須用戶編寫複雜Sql,不支持複合主鍵
  row:不支持sqlServer2000

測試數據:
共320萬條數據,每頁顯示10條數據,分別測試了2萬頁、15萬頁和32萬頁。

頁碼,top方案,max方案,row方案
2萬,60ms,46ms,33ms
15萬,453ms,343ms,310ms
32萬,953ms,720ms,686ms


具體操作sql代碼如下:

top方案:

select top 10 * from Table1
where Id not in(select top 開始的位置 Id from Table1)


max:

select top 10 * from Table1
where Id>(select max(Id)
from (select top 開始位置 Id from Table1 order by Id)tt)

row:

select*
from (
select row_number() over(order by tempColumn) tempRowNumber,*
from (select top 開始位置+10 tempColumn=0,* from Table1)t
)tt
where tempRowNumber>開始位置


參考:http://topic.csdn.net/u/20100617/04/80d1bd99-2e1c-4083-ad87-72bf706cb536.html




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章