LIMIT offset, size 機制:掃描 offset + size 行,丟棄前 offset 行。Offset 越大,掃描越多,速度越慢。
SELECT * FROM articles LIMIT 100000, 20;
-- 假設 id 為自增主鍵,每頁 20 條,第 5001 頁
SELECT a.*
FROM articles a
INNER JOIN (
SELECT id FROM articles
WHERE id > 100000 ORDER BY id LIMIT 20
) b USING (id);
WHERE id > (page-1)*page_size 替代 OFFSETSELECT * FROM articles
WHERE id > 100000
ORDER BY id ASC
LIMIT 20;
ASC 索引順序掃描,DESC 會導致 filesort(8.0+ 已優化)PREPARE stmt FROM
'SELECT * FROM articles WHERE id > ? ORDER BY id LIMIT ?';
SET @offset = 100000, @limit = 20;
EXECUTE stmt USING @offset, @limit;
CREATE PROCEDURE sp_page_articles(IN p_offset INT, IN p_limit INT)
BEGIN
SELECT * FROM articles
WHERE id > p_offset ORDER BY id LIMIT p_limit;
END;
-- 首頁
SELECT * FROM articles ORDER BY id LIMIT 20;
-- 下一頁:使用上一頁最後一條 id 作為游標
SELECT * FROM articles WHERE id > 100020 ORDER BY id LIMIT 20;
| 方案 | 第 1 頁 | 第 100 頁 | 第 10000 頁 | 穩定性 | 適用場景 |
|---|---|---|---|---|---|
| LIMIT offset | 5ms | 50ms | 2000ms+ | 需 ORDER BY | 小資料、後台管理 |
| 子查詢 Join | 4ms | 6ms | 8ms | 高 | 主鍵連續、傳統分頁 |
| WHERE id > offset | 3ms | 5ms | 6ms | 高 | 主鍵連續、已知上頁最大 ID |
| Prepared | 3ms | 5ms | 6ms | 高 | 高併發固定查詢 |
| 存儲程序 | 2ms | 4ms | 5ms | 高 | 極高頻、邏輯固定 |
| Keyset/Cursor | 3ms | 5ms | 5ms | 最高 | API 無限滾動、大數據導出 |
需要跳頁(任意頁碼)?
├─ 是 → 資料量 < 10萬? → 是 → 方案一 LIMIT
│ └─ 否 → 方案三 WHERE id > offset + ORDER BY
└─ 否(僅上一頁/下一頁/無限滾動)
→ 方案六 Keyset Pagination (首選)
→ 或方案三(需相容舊版瀏覽器)
SELECT *,只查需要欄位(覆蓋索引)SQL_CALC_FOUND_ROWS + FOUND_ROWS() 獲取總數:MySQL 8.0 棄用,改用單獨 COUNT(*) 查詢