服務器端幾種分頁方式的性能分析
——by comaple 2011-6-17
前言:
本試驗在於探討分頁的性能問題,當然客戶端分頁也是一種分頁的策略。不過這種分頁方式已經過時了,建議不要採用。這裏我們只討論服務器端分頁。
實驗環境:
Pentium(R) dual-Core CPU E5300 @ 2.6GHz 2.59GHz, 2.00GB內存
SqlServer2008 數據庫環境,數據庫中我們要用到的的表:
dbo.GMpipe
CREATE TABLE [dbo].[GMpipe](
[GMDataID] [uniqueidentifier] NOT NULL,
[pointID] [uniqueidentifier] NULL,
[measurePipe] [varchar](10) NULL,
[measureTime] [datetime] NULL,
[measureCycle] [varchar](10) NULL,
[MeasureData] [int] NULL,
[doseRateValue] [decimal](18, 10) NULL,
CONSTRAINT [PK_GMPIPE] PRIMARY KEY CLUSTERED
(
[GMDataID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
目前該表中存在1157226條數據,用select語句查詢耗時爲:17s
SELECT * FROM dbo.GMpipe ORDER BY measureTime DESC
接下來我們就來一起體驗一下把:
第一種方式
使用top語句(本文只列出常用的):
分頁的存儲過程,已實現好了如下:
CREATE PROCEDURE paging1
@pageNum INT –-頁碼
,@Num INT --每頁條數
AS
BEGIN
SELECT TOP (@Num) * FROM
(
SELECT TOP (@Num*@pageNum) * FROM dbo.GMpipe ORDER BY dbo.GMpipe.measureTime asc
) b ORDER BY b.measureTime DESC;
END
go
這個中方法先把數據庫中的前@Num*@pageNum條數據取出,再從結果集中取出最後的@Num條數據,當然兩個排序規則是不一樣的這點很重要,不然起不到分頁效果。 你可以具體試一下就明白了。
看性能
EXEC paging1 2,5;--每頁五條,第十頁數據 耗時:1s
EXEC paging1 200,5;--每頁五條,第200頁數據 耗時:1s
EXEC paging1 20000,5;--每頁五條,第20000頁數據 耗時:1s
EXEC paging1 200000,5;--每頁五條,第二十萬頁數據 耗時: 3s
第二中方式
使用臨時表
分頁的存儲過程,實現如下:
CREATE PROCEDURE paging2
@pageNum INT
,@Num INT
AS
BEGIN
SELECT measurePipe,measureTime,measureCycle,MeasureData,doseRateValue,IDENTITY(int) Num INTO #temp FROM dbo.GMpipe ORDER BY measureTime ASC
SELECT * FROM #temp WHERE Num<=@Num*@pageNum AND Num> @Num*(@pageNum-1)
ORDER BY Num ASC
DROP TABLE #temp
END
Go
這種方式是將表中的數據全部查出,然後加入標識行號的列Num並將其裝入臨時表#temp中然後可根據行號列進行分頁查詢。
看性能
EXEC paging2 2,5;--每頁五條,第二頁數據 耗時:3s
EXEC paging2 200,5;--每頁五條,第二百頁數據 耗時:3s
EXEC paging2 20000,5;--每頁五條,第二萬頁數據 耗時:3s
EXEC paging2 200000,5;--每頁五條,第二十萬頁數據 耗時:3s
第三種方式
採用系統提供的ROW_NUMBER()函數
存儲過程實現如下:
CREATE PROCEDURE paging0
@pageNum INT
,@Num INT
AS
begin
SELECT * FROM
(
SELECT measurePipe,measureTime,measureCycle,MeasureData,doseRateValue,ROW_NUMBER() OVER(ORDER BY GMpipe.measureTime ASC ) AS NUM
FROM GMpipe)A
WHERE A.NUM<=@Num*@pageNum AND A.NUM> @Num*(@pageNum-1) ORDER BY A.measureTime desc
END
Go
這種方式就不多說了大家一看就明白,直接看性能。
看性能
EXEC paging0 20,5;--每頁五條,第二十頁數據 耗時: 1s
EXEC paging0 20000,5;--每頁五條,第二萬頁數據 耗時: 1s
EXEC paging0 200000,5;--每頁五條,第二十萬頁數據 耗時: 1s
改進第三種方式:
之所以要改進第三種方式那是因爲,Top關鍵字其實是
已經經過性能優化了的之所以比不過ROW_NUMBER()的執行效率是因爲用了兩次,那麼既然如此,我們何不將二者結合起來使用,效果豈不更佳。那就讓我們改進一下吧。
CREATE PROCEDURE paging0
@pageNum INT
,@Num INT
AS
begin
SELECT * FROM
(
SELECT TOP (@Num*@pageNum) measurePipe,measureTime,measureCycle,MeasureData,
doseRateValue,ROW_NUMBER() OVER(ORDER BY GMpipe.measureTime ASC ) AS NUM
FROM GMpipe)A
WHERE A.NUM> @Num*(@pageNum-1) ORDER BY A.measureTime desc
END
Go
這樣一來執行效率更高了呵呵!
總結
我們再來改變一下每頁的條數看看
臨時表方式:
EXEC paging2 5000,200;--每頁兩百條,第五千頁數據 耗時:7s
Top語句方式:
EXEC paging1 5000,200;-- 每頁兩百條,第五千頁數據 耗時: 3s
ROW_NUMBER()函數方式:
EXEC paging0 5000,200;--每頁五條,第二十萬頁數據 耗時:1s
分析:這樣我們就能看到很清楚了吧,影響top語句方式的因素是你要取的頁數,即越靠後耗時也明顯。影響臨時表的因素則比較多了首先是數據的總條數,其次是分頁方式即每頁的數據量。而ROW_NUMBER()函數的影響則可能只有總的數據量,並且性能可是不錯的哦!
我想對與一般的系統而言二十萬頁的數據分頁量已經夠用了吧,呵呵!再多的話我們也看不過來啊