相比在SQL Server 2000 中使用的分頁方式,在 SQL Server 2005 中使用新的語法 ROW_NUMBER() 來分頁效率要高出很多,但是很多人在使用 ROW_NUMBER() 這種分頁方式時,使用的方法並不正確,以下列出不正確的和正確的做法並做簡單分析:
首先假設我們已經創建瞭如下的表和索引並初始化了100 萬條數據:
CREATE TABLE [dbo].[Users]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL,
[test] [nchar](10) NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED
(
[ID] ASC
) ON [PRIMARY]
) ON [PRIMARY]
CREATE UNIQUE NONCLUSTERED INDEX [Inx_Name] ON [dbo].[Users]
(
[Name] ASC
) ON [PRIMARY]
DECLARE @index INT
SET @index=0
WHILE @index<1000000
BEGIN
INSERT INTO Users(Name,test) values(@index,'walkingp')
SET @index = @index + 1
END
不正確的使用方式( 查出所有數據後再排序 ) :
select Id,Name,test from (select row_number() over(order by name) as rowNum,* from users) as t where rowNum between 5000 and 5100
正確的使用方式如下( 查出主鍵進行排序過濾,然後使用過濾後的主鍵來查找數據 ) :
select a.Id,a.Name,a.test from users as a inner join (select rowNum,id from (select row_number() over(order by name) as rowNum,ID from users) as t where rowNum between 4000 and 4100) as b on a.id = b.id order by b.rownum
錯誤的使用方式邏輯讀要比正確的使用方式的邏輯讀大的多,而且頁碼越大讀的越多,最終導致效率越來越差,這點也可以通過執行計劃看出端倪。
以下是執行計劃:
通過對比執行計劃我們發現錯誤的使用方式在一開始就要讀取聚集索引的數據分頁中的數據,而正確的使用方式在一開始只是讀取Inx_Name 所引的所有數據分析,這在最後查出 101 條數據後才從聚集索引的數據分頁中查找數據,因此效率要高的多,這種方式應該是創建此類 SQL 的一個通用原則。