SQL Server 中的三種分頁方式

2022-03-07 09:38:48 字數 4065 閱讀 7133

use

tempdb

goset nocount on

--建立表結構

ifobject_id(n'

classb

', n'

u') is

notnull

drop

table

classb

gocreate

table classb(id int

primary

key, name varchar(16), createdate datetime, aid int, status int

)create

index idx_createdate on

classb(createdate)

create

index idx_aid on

classb(aid)

go--

插入測試資料

declare

@idint

set@id=1

while

@id<=

100000

begin

insert

into classb values(@id, '

fx', getdate(), @id

%20, @id%20

)

set@id

=@id+1

end--

統計總行數

select

'classb

'as classb, count(1) as

count

from classb

查詢條件如下:根據createdate倒序排序,createdate一致時按照id倒序;時間區間在2014-07-13和2014-07-14之間;每頁20條,當前頁數第3頁;

方案a:雙top,取出之前頁的所有id後,使用not in排除這些id進行查詢,這是效能最差一種,因為他使用相同的查詢謂詞,查詢了兩次資料,且兩次排序;

declare

@page_size

int=20;

declare

@page_index

int=3;

--a: 雙top:取出之前頁的所有id後,使用not in排除這些id進行查詢,效能最差

with id_list_excluded as

(

select

top (@page_size

* (@page_index

-1)) id from classb where createdate between

'2014-07-13

'and

'2014-07-14

'order

by createdate desc, id desc

)select

top (@page_size) *

from classb where id not

in (select id from id_list_excluded) and createdate between

'2014-07-13

'and

'2014-07-14

'order

by createdate desc, id desc;

表 'classb'。掃瞄計數 2,邏輯讀取 136 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

表 'worktable'。掃瞄計數 1,邏輯讀取 197 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

查詢頁數越靠後邏輯讀取,下面是查詢第30頁的邏輯讀取情況:

表 'classb'。掃瞄計數 2,邏輯讀取 1243 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

表 'worktable'。掃瞄計數 1,邏輯讀取 2574 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

方案b:row_number,取出截止到當前頁所有符合查詢謂詞的記錄,並給每條記錄加上序號,然後根據序號查詢,效能次之;

declare

@page_size

int=20;

declare

@page_index

int=3;

--b: row_number:取出截至到當前頁所有符合查詢謂詞的記錄,並給每條記錄加上序號,然後根據序號查詢,效能次之

with newclassb as

(

select

top (@page_size

*@page_index) row_number() over (order

by createdate desc, id desc) as rowid, *

from

classb

where createdate between

'2014-07-13

'and

'2014-07-14')

select

top (@page_size) *

from

newclassb

where rowid between (@page_size

* (@page_index

-1) +

1) and (@page_size

*@page_index);

表 'classb'。掃瞄計數 1,邏輯讀取 134 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

方案b已經比方案a快了近一倍,少了乙個worktable,同樣,page_index越大,掃瞄次數越多,因為子查詢中要查詢多餘的(之前頁)資料和字段,下面是查詢第30頁時的io讀取情況;

表 'classb'。掃瞄計數 1,邏輯讀取 1241 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

方案c:雙top,取出截止到當前頁為止的所有的id,去掉之前頁的id,然後根據id(通常是主鍵)作常規查詢,效能最優;

declare

@page_size

int=20;

declare

@page_index

int=3;

with id_list as

(

select

top (@page_size

*@page_index) id from

classb

where createdate between

'2014-07-13

'and

'2014-07-14

'order

by createdate desc, id desc

),id_list_current as(

select id from id_list where id not

in(select

top (@page_size

* (@page_index

-1)) id from

id_list)

)select

*from classb where id in (select id from id_list_current);

表 'classb'。掃瞄計數 2,邏輯讀取 52 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

查詢第30頁的資料僅比查詢第3頁的資料多出兩次邏輯讀取,方案c和b的唯一在於:子查詢中的查詢列,方案b中返回了所有字段,所有要通過聚集索引走lookup,而方案c直接返回索引鍵即可。

表 'classb'。掃瞄計數 2,邏輯讀取 54 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

SQL Server的三種分頁方式

目前常見的三種sql分頁方式 top not in方式 select top 條數 from tablename where id not in select top 條數 頁數 id from tablename row number over 方式 select from select row ...

sqlserver三種分頁查詢方法

假設有表student,每頁顯示10條記錄,查詢第5頁的內容。from student where idnotin 40是這麼計算出來的 10 5 1 select top 40 idfrom student order byid order by id原理 需要拿出資料庫的第5頁,就是40 50條...

SqlServer 三種分頁查詢語句

先說好吧,查詢的資料排序,有兩個地方 1 分頁前的排序。2 查詢到當前頁資料後的排序 1 先查詢當前頁碼之前的所有資料id select top 當前頁數 1 每頁資料條數 id from 表名 2 再查詢所有資料的前幾條,但是id不在之前查出來的資料中 select top 每頁資料條數 from...