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

SQL Server 2005 高效分頁新技巧:ROW_NUMBER() 等 Ranking 函數取代臨時表 Identity 法

     編輯:關於SqlServer

SQL Server 2000 分頁常用「建立含 Identity 的暫存表 → 插入排序結果 → 依 Identity 篩選頁碼」,效能差、程式碼繁。SQL 2005 引入 ROW_NUMBER()、RANK()、DENSE_RANK()、NTILE() 等視窗函數,單一查詢即可完成高效分頁。

SQL 2000 傳統寫法 (效能痛點)


CREATE PROC northwind_OrdersPaged @PageIndex INT, @PageSize INT
AS
SET ROWCOUNT @PageSize * (@PageIndex + 1);
CREATE TABLE #PageIndex (IndexId INT IDENTITY(1,1), OrderID INT);
INSERT #PageIndex (OrderID) SELECT OrderID FROM Orders ORDER BY OrderID DESC;
SELECT COUNT(OrderID) FROM Orders;
SELECT O.* FROM Orders O, #PageIndex P
WHERE O.OrderID = P.OrderID AND P.IndexId > @PageSize*@PageIndex AND P.IndexId <= @PageSize*(@PageIndex+1)
ORDER BY P.IndexId;

缺點:SET ROWCOUNT 影響後續陳述式、暫存表寫入/讀取 IO、IDENTITY 間隙導致頁碼偏移。

SQL 2005+ 標準分頁寫法 (ROW_NUMBER)


CREATE PROC Orders_Paged_2005
    @PageIndex INT = 0,   -- 0-based
    @PageSize  INT = 20
AS
BEGIN
    SET NOCOUNT ON;

    ;WITH Numbered AS (
        SELECT
            ROW_NUMBER() OVER (ORDER BY OrderID DESC) AS RowNum,
            OrderID, CustomerID, EmployeeID, OrderDate, RequiredDate, ShippedDate,
            ShipVia, Freight, ShipName, ShipAddress, ShipCity, ShipRegion,
            ShipPostalCode, ShipCountry
        FROM dbo.Orders
    )
    SELECT *
    FROM Numbered
    WHERE RowNum BETWEEN @PageIndex * @PageSize + 1 AND (@PageIndex + 1) * @PageSize
    ORDER BY RowNum;

    -- 總筆數 (可分開查詢或加 COUNT() OVER)
    SELECT COUNT(*) FROM dbo.Orders;
END;
GO

進階:OFFSET/FETCH (SQL 2012+ 更簡潔)


SELECT OrderID, CustomerID, OrderDate
FROM dbo.Orders
ORDER BY OrderID DESC
OFFSET @PageIndex * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;
  • 語法標準化 (ANSI SQL:2008)、最佳化器可直接產生 Top-N Sort 計畫
  • 搭配 COUNT(*) OVER() 可單查詢回傳總筆數與分頁資料

Ranking 函數家族快速對照

效能優化關鍵

  1. 索引支援 ORDER BY:分頁欄位建立覆蓋索引,避免 Key Lookup
  2. 避免 SELECT *:只取需要欄位,減少輸出 IO
  3. 深分頁優化:頁碼極大 (如第 10 萬頁) 時,OFFSET 仍需掃描前 N 列 → 改用 Keyset Pagination (游標式) WHERE OrderID < @LastSeenId ORDER BY OrderID DESC LIMIT @PageSize
  4. 總筆數分離:COUNT(*) 獨立查詢並快取,避免每頁重複掃描

遷移建議

現有 SQL 2000 分頁預存程序 → 直接改寫為 ROW_NUMBER() CTE 版本,測試通過後部署。若仍在 SQL 2000,可用 TOP + 子查詢模擬 (效能較差) 或升級資料庫相容性等級。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
函數行為典型用途
ROW_NUMBER()連續不重複 1,2,3...**分頁、去重取第一筆**
RANK()相同值同序,下一序跳號 (1,2,2,4)排名榜、並列名次
DENSE_RANK()相同值同序,下一序不跳 (1,2,2,3)密集排名、分組排序
NTILE(n)分成 n 桶,均勻分配四分位數、百分位、分桶分析