適用於 SQL Server 2005+,標準、高效、支持任意頁碼跳轉。
DECLARE @PageSize INT = 10, -- 每頁條數
@PageIndex INT = 4; -- 當前頁碼 (從 1 開始)
SELECT *
FROM (
SELECT
t.*,
ROW_NUMBER() OVER (ORDER BY Id DESC) AS RowNum -- 排序欄位按業務調整
FROM YourTable t
) AS PagedData
WHERE RowNum BETWEEN (@PageIndex - 1) * @PageSize + 1
AND @PageIndex * @PageSize
ORDER BY RowNum;
| 元素 | 說明 |
|---|---|
| ROW_NUMBER() OVER (ORDER BY ...) | 為結果集按指定排序生成連續行號 (從 1 開始)。 |
| 子查詢別名 (PagedData) | 窗口函數結果必須在外層引用,不能直接在 WHERE 中使用。 |
| BETWEEN 範圍計算 | 第 N 頁 = (N-1)*Size+1 到 N*Size。例:第 4 頁、每頁 10 條 → 31-40。 |
| 外層 ORDER BY RowNum | 保證最終輸出順序與分頁邏輯一致。 |
-- 缺點:性能隨頁碼增大急劇下降,不推薦大數據量深分頁
SELECT TOP 10 *
FROM UserInfo
WHERE Id NOT IN (
SELECT TOP 30 Id FROM UserInfo ORDER BY Id -- 跳過前 3 頁 (3*10)
)
ORDER BY Id;
SELECT *
FROM YourTable
ORDER BY Id DESC
OFFSET (@PageIndex - 1) * @PageSize ROWS -- 跳過前 N 行
FETCH NEXT @PageSize ROWS ONLY; -- 取後 M 行
ORDER BY 使用。| 方案 | 適用版本 | 深分頁性能 | 代碼複雜度 | 推薦指數 |
|---|---|---|---|---|
| ROW_NUMBER() | 2005+ | 良好 (需覆蓋索引支持) | 中等 | ⭐⭐⭐⭐ |
| OFFSET FETCH | 2012+ | 優秀 (優化器原生支持) | 低 | ⭐⭐⭐⭐⭐ |
| TOP + NOT IN | 2000+ | 極差 (隨頁碼線性惡化) | 低 | ⭐ (僅小數據/教學) |
| 游標/臨時表 | 所有 | 可控但開發維護成本高 | 高 | ⭐⭐ (特殊業務) |
分頁查詢性能核心在於 ORDER BY 列上有合適索引:
-- 創建測試表
CREATE TABLE dbo.TestPaging (
Id INT IDENTITY(1,1) PRIMARY KEY,
Name VARCHAR(50),
CreateTime DATETIME DEFAULT GETDATE()
);
INSERT INTO dbo.TestPaging (Name)
SELECT TOP 1000 'Item_' + CAST(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS VARCHAR)
FROM sys.objects a, sys.objects b;
-- 分頁存儲過程
CREATE PROCEDURE dbo.sp_GetPagedData
@PageIndex INT = 1,
@PageSize INT = 20,
@TotalCount INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT @TotalCount = COUNT(*) FROM dbo.TestPaging;
SELECT Id, Name, CreateTime
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY Id DESC) AS RowNum
FROM dbo.TestPaging
) t
WHERE RowNum BETWEEN (@PageIndex - 1) * @PageSize + 1 AND @PageIndex * @PageSize
ORDER BY RowNum;
END
GO
-- 測試調用
DECLARE @Total INT;
EXEC dbo.sp_GetPagedData @PageIndex = 3, @PageSize = 10, @TotalCount = @Total OUTPUT;
PRINT '總記錄數: ' + CAST(@Total AS VARCHAR);