首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 分頁查詢三大演算法實測:TOP N、暫存表、ROW_NUMBER 效能大比拚

     編輯:關於SqlServer

測試環境

  • Windows Server 2003 / Intel Core2 6300 / 4 GB RAM
  • SQL Server 2005 Enterprise (9.00.3054)
  • 測試表 tb_group:300 萬列,PK 為 ID (CLUSTERED),非索引欄位 country

三種分頁實作

1. TOP N 雙重巢狀 (傳統相容)


-- 第 1 頁
SELECT TOP @PageSize * FROM tb_group ORDER BY Country ASC;

-- 第 N 頁 (N>1)
SELECT TOP @PageSize * FROM (
    SELECT TOP @PageSize*@PageIndex * FROM tb_group ORDER BY Country ASC
) t ORDER BY Country DESC;

2. 暫存表 + IDENTITY 序號


CREATE TABLE #Pager (ID INT, PagerID INT IDENTITY(1,1));
INSERT INTO #Pager (ID)
SELECT TOP @PageSize*@PageIndex ID FROM tb_group ORDER BY Country ASC;

SELECT g.* FROM tb_group g
JOIN #Pager p ON g.ID = p.ID
WHERE p.PagerID BETWEEN @PageSize*(@PageIndex-1)+1 AND @PageSize*@PageIndex;
DROP TABLE #Pager;

3. ROW_NUMBER() 視窗函數 (SQL 2005+)


SELECT * FROM (
    SELECT *, ROW_NUMBER() OVER (ORDER BY Country ASC) AS RowNo
    FROM tb_group
) t
WHERE RowNo BETWEEN @PageSize*(@PageIndex-1)+1 AND @PageSize*@PageIndex;

測試結果 (毫秒)

測試案例TOP N (無索引)TOP N (有索引)暫存表 (無索引)暫存表 (有索引)ROW_NUMBER (無索引)ROW_NUMBER (有索引)
第 10 頁 (30/頁)65,22028027,4072,6279,107250
第 1,000 頁67,00064028,1702,8739,873263
第 10,000 頁67,00051731,5005,78312,230517
第 100,000 頁 (20/頁)75,0002,64045,93715,75019,6401,983

深度分析

方法優點缺點適用場景
TOP N無版本限制、索引排序極快無索引排序極慢;末頁邏輯複雜;重複排序值需二次排序SQL 2000、有索引排序、中小資料量
暫存表邏輯直觀、支援複雜排序寫入 tempdb 產生 I/O 壓力;大資料量嚴重拖慢無索引排序、一次性報表、可接受秒級
ROW_NUMBER語法簡潔、單次掃描、有無索引表現穩定、支援 PARTITION需 SQL 2005+;極大資料量無索引仍較慢首選方案 (SQL 2005+)

關鍵發現

  1. 索引是分頁效能的決定性因素:有索引排序時,三種方法差距縮小至毫秒級;無索引時差距達數十倍。
  2. ROW_NUMBER 穩定性最佳:隨頁碼增長,時間增長呈線性,無劇烈跳動。
  3. 深分頁 (10萬頁) 仍有效能挑戰:即使 ROW_NUMBER,無索引需 19 秒。解決方案:
      • 強制建立排序欄位索引
      • 使用「游標式分頁」:WHERE ID > @LastMaxID ORDER BY ID OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY
      • 應用層限制最大頁碼或改用無限捲動

遺留問題:ROW_NUMBER 大小寫 Bug?

測試發現小寫 row_number() 報錯,大寫 ROW_NUMBER() 正常。經驗證為查詢編輯器字型/編碼顯示問題,實際執行不分大小寫。建議統一大寫關鍵字。

最佳實務建議


-- 通用分頁存儲過程範本 (SQL 2012+ OFFSET/FETCH 更簡潔)
CREATE PROC usp_Pager
    @TableName SYSNAME,
    @OrderBy   SYSNAME,
    @PageSize  INT = 20,
    @PageIndex INT = 1,
    @Where     NVARCHAR(MAX) = ''
AS
BEGIN
    DECLARE @SQL NVARCHAR(MAX) = N'
        SELECT * FROM (
            SELECT *, ROW_NUMBER() OVER (ORDER BY ' + QUOTENAME(@OrderBy) + ') AS RN
            FROM ' + QUOTENAME(@TableName) + 
            CASE WHEN @Where <> '' THEN ' WHERE ' + @Where ELSE '' END + '
        ) t WHERE RN BETWEEN ' + CAST((@PageIndex-1)*@PageSize+1 AS VARCHAR) + 
        ' AND ' + CAST(@PageIndex*@PageSize AS VARCHAR);
    EXEC sp_executesql @SQL;
END;
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved