首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

SQL Server 分頁查詢兩大經典寫法對比:TOP NOT IN vs ROW_NUMBER()

     編輯:MySQL 資料庫相關知識

測試環境

表 T_News,主鍵 id,每頁 3 筆。

寫法一:TOP + NOT IN(舊版相容,效能較差)

-- 第 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 確保確定性,否則結果不穩定。

寫法二:ROW_NUMBER() OVER()(SQL Server 2005+,標準高效)

-- 第 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)
11210
10045015
1000420018
10000超時22

進階:OFFSET FETCH (SQL Server 2012+)

SELECT * FROM T_News
ORDER BY id
OFFSET (@pagenum-1)*@pagesize ROWS FETCH NEXT @pagesize ROWS ONLY;

語法最簡潔,執行計畫同 ROW_NUMBER,推薦新專案直接使用。

MySQL/PostgreSQL 対應寫法

-- MySQL / PostgreSQL
SELECT * FROM t_news ORDER BY id LIMIT @pagesize OFFSET (@pagenum-1)*@pagesize;

總結建議

  • SQL Server 2012+:首選 OFFSET FETCH。
  • SQL Server 2005-2008 R2:用 ROW_NUMBER()。
  • 避免 TOP NOT IN 深分頁,僅適合極小資料量或教學示範。
  • 所有分頁必須帶 確定性 ORDER BY(最好含主鍵),否則結果不穩定。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved