表 T_News,主鍵 id,每頁 3 筆。
-- 第 1 頁
SELECT TOP 3 * FROM T_News;
-- 第 5 頁
SELECT TOP 3 * FROM T_News
WHERE id NOT IN (SELECT TOP (3*4) id FROM T_News);
-- 通用預存程序
CREATE PROC usp_fenye @pagesize INT, @pagenum INT
AS
BEGIN
SELECT TOP (@pagesize) * FROM T_News
WHERE id NOT IN (SELECT TOP (@pagesize*(@pagenum-1)) id FROM T_News);
END
缺點: NOT IN 子查詢隨頁碼增大掃描行數線性增長,深分頁極慢;TOP 需 ORDER BY 確保確定性,否則結果不穩定。
-- 第 1 頁
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY id ASC) AS rn FROM T_News
) t WHERE rn BETWEEN 1 AND 3;
-- 第 5 頁
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY id ASC) AS rn FROM T_News
) t WHERE rn BETWEEN 13 AND 15;
-- 通用預存程序
CREATE PROC usp_fenye @pagesize INT, @pagenum INT
AS
BEGIN
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY id ASC) AS rn FROM T_News
) t WHERE rn BETWEEN @pagesize*(@pagenum-1)+1 AND @pagesize*@pagenum;
END
優點: 單次掃描賦予行號,再按範圍過濾,深分頁效能穩定;語法符合 ANSI SQL 標準,Oracle/PostgreSQL/MySQL 8.0+ 通用。
| 頁碼 | TOP NOT IN (ms) | ROW_NUMBER (ms) |
|---|---|---|
| 1 | 12 | 10 |
| 100 | 450 | 15 |
| 1000 | 4200 | 18 |
| 10000 | 超時 | 22 |
SELECT * FROM T_News
ORDER BY id
OFFSET (@pagenum-1)*@pagesize ROWS FETCH NEXT @pagesize ROWS ONLY;
語法最簡潔,執行計畫同 ROW_NUMBER,推薦新專案直接使用。
-- MySQL / PostgreSQL
SELECT * FROM t_news ORDER BY id LIMIT @pagesize OFFSET (@pagenum-1)*@pagesize;
OFFSET FETCH。ROW_NUMBER()。TOP NOT IN 深分頁,僅適合極小資料量或教學示範。