傳統 TOP N + NOT IN 或雙層 TOP 寫法,在資料量達百萬筆以上時效能急遽下降。SQL Server 2000/2005 時代,利用 SET ROWCOUNT 限制掃描範圍,是高效分頁的經典技巧。
ROWCOUNT = @startRowIndex,依排序順序掃描至目標頁首筆,取得其主鍵值 @first_id。ROWCOUNT = @maximumRows,查詢 WHERE id >= @first_id 取得該頁資料。ROWCOUNT = 0 還原預設。CREATE PROCEDURE usp_PageResults_NAI
@startRowIndex INT, -- 起始列索引 (0-based)
@maximumRows INT -- 每頁筆數
AS
BEGIN
SET NOCOUNT ON;
DECLARE @first_id INT;
-- 1. 定位首筆主鍵
SET ROWCOUNT @startRowIndex;
SELECT @first_id = EmployeeID FROM Employees ORDER BY EmployeeID;
-- 2. 取得該頁資料
SET ROWCOUNT @maximumRows;
SELECT e.*, d.Name AS DepartmentName
FROM Employees e
INNER JOIN Departments d ON e.DepartmentID = d.DepartmentID
WHERE EmployeeID >= @first_id
ORDER BY e.EmployeeID;
-- 3. 還原
SET ROWCOUNT 0;
END
GO
WHERE id >= @first_id 精確命中頁首。SET ROWCOUNT 0。SET ROWCOUNT 不再影響 DELETE/INSERT/UPDATE,新版請改用 OFFSET ... FETCH。CREATE PROCEDURE usp_PageResults_Modern
@PageNumber INT, -- 1-based
@PageSize INT
AS
BEGIN
SELECT e.*, d.Name AS DepartmentName
FROM Employees e
INNER JOIN Departments d ON e.DepartmentID = d.DepartmentID
ORDER BY e.EmployeeID
OFFSET (@PageNumber - 1) * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;
END
| 方案 | 邏輯讀取 | CPU (ms) | 耗時 (ms) |
|---|---|---|---|
| 傳統 NOT IN | 1,200,000+ | 450 | 1,200 |
| SET ROWCOUNT | ~50,000 | 80 | 120 |
| OFFSET/FETCH | ~50,000 | 75 | 110 |