傳統 LIMIT offset, size 深分頁 (大 offset) 需掃描大量行再丟棄,效能極差。利用窗口函數 ROW_NUMBER() 先標記序號再篩選,僅讀取顯示資料。
CREATE DATABASE TestForPaging;
USE TestForPaging;
CREATE TABLE SomeData (
id INT PRIMARY KEY,
name VARCHAR(30),
description TEXT
);
INSERT INTO SomeData VALUES
(1,'num1','第1條'), (2,'num2','第2條'), (3,'num3','第3條'),
(4,'num4','第4條'), (5,'num5','第5條');
SELECT name, description,
ROW_NUMBER() OVER (ORDER BY id DESC) AS dataLevel
FROM SomeData;
SELECT dataLevel, name, description FROM (
SELECT name, description,
ROW_NUMBER() OVER (ORDER BY id DESC) AS dataLevel
FROM SomeData
) AS datawithlevel
WHERE dataLevel BETWEEN 2 AND 4;
CREATE PROCEDURE GetDataPaged
@startRowIndex INT,
@maximumRows INT,
@sort VARCHAR(50)
AS
IF LEN(@sort) = 0 SET @sort = 'id';
SELECT dataLevel, name, description FROM (
SELECT name, description,
ROW_NUMBER() OVER (ORDER BY @sort DESC) AS dataLevel
FROM SomeData
) AS datawithlevel
WHERE dataLevel > (@startRowIndex * 10)
AND dataLevel <= (@startRowIndex * 10 + @maximumRows);
注意:此語法為 SQL Server (T-SQL)。MySQL 8.0+ 同樣支援 ROW_NUMBER() OVER (),參數化排序需動態 SQL 或應用層組裝。
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY id DESC) AS rn
FROM SomeData
) t WHERE rn > (page-1)*pageSize AND rn <= page*pageSize;
配合覆蓋索引 (id, name, description) 可實現純索引掃描,極大提升百萬級資料分頁效能。