語法速查
SELECT select_list
FROM table_name
[WHERE condition]
[ORDER BY column_list]
LIMIT [offset,] row_count
-- 等價寫法
LIMIT row_count OFFSET offset
核心用法
| 需求 | 寫法 | 說明 |
| 前 N 行 (Top-N) | LIMIT N | offset=0 省略 |
| 第 M+1 到 M+N 行 | LIMIT M, N | M=offset,N=row_count |
| 分頁第 P 頁 (每頁 S 條) | LIMIT (P-1)*S, S | 應用層計算 offset |
經典範例
-- 最新 10 條訂單
SELECT * FROM orders ORDER BY created_at DESC LIMIT 10;
-- 第 3 頁,每頁 20 條
SELECT * FROM products WHERE status=1 ORDER BY id LIMIT 40, 20;
-- 配合 OFFSET 關鍵字 (可讀性更好)
SELECT * FROM logs ORDER BY id DESC LIMIT 100 OFFSET 1000;
性能陷阱:大 Offset 深分頁問題
現象:LIMIT 1000000, 20 需掃描並丟棄 100 萬行,隨 Offset 線性增長,延遲從 ms 級飆升至秒級。
根因:MySQL 無法「跳過」索引節點,必須遍歷 offset 行後再取 row_count 行。
優化方案對比
| 方案 | 適用場景 | 原理 | 優/缺點 |
| 延遲關聯 | 單表、有覆蓋索引 | 子查詢只取 PK,再回表 | + 索引掃描極快 - 需覆蓋索引 |
| 書籤/游標分頁 | 無限滾動、ID 遞增 | WHERE id > last_id LIMIT 20 | + 無 Offset、極快 - 不支援跳頁、需唯一遞增鍵 |
| 覆蓋索引 + 僅查 PK | 需回表列少 | 索引包含所有查詢列 | + 避免回表 - 索引膨脹 |
| 應用層緩存 | 熱門首頁、固定分頁 | Redis 緩存頁面數據 | + 極快 - 數據實時性妥協 |
延遲關聯實戰
-- 慢:掃描 100 萬行
SELECT * FROM orders WHERE user_id=123 ORDER BY id DESC LIMIT 1000000, 20;
-- 快:子查詢只走覆蓋索引 (user_id, id)
SELECT o.* FROM orders o
INNER JOIN (
SELECT id FROM orders WHERE user_id=123 ORDER BY id DESC LIMIT 1000000, 20
) tmp USING (id);
配合 ORDER BY 的索引設計
ORDER BY a LIMIT N → 索引 (a) 或 (a, ...)
WHERE b=1 ORDER BY a LIMIT N → 索引 (b, a) (等值在前、排序在後)
WHERE b>1 ORDER BY a LIMIT N → 索引 (b, a) 可能用不上排序部分 (範圍查詢截斷)
- 使用
EXPLAIN 觀察 Using index、Using filesort
避坑指南
- 無 ORDER BY 的 LIMIT 不確定性:結果集順序不穩定,必須加排序
- OFFSET 0 無意義:
LIMIT 0, 10 等同 LIMIT 10
- 負數/超大值:Offset 負數報錯;超大 Offset 返回空集,不報錯
- Prepared Statement 參數化:
LIMIT ?, ? 防注入、複用執行計劃
- 計算總數分離:
SELECT COUNT(*) 走覆蓋索引;分頁查詢走 LIMIT,避免 SQL_CALC_FOUND_ROWS (已棄用)
現代替代:Keyset Pagination (無限滾動首選)
-- 首頁
SELECT * FROM posts WHERE status=1 ORDER BY created_at DESC, id DESC LIMIT 20;
-- 下一頁 (記住最後一條的 created_at, id)
SELECT * FROM posts
WHERE status=1
AND (created_at < '2024-01-15 10:30:00' OR (created_at = '2024-01-15 10:30:00' AND id < 98765))
ORDER BY created_at DESC, id DESC LIMIT 20;
優勢:無 Offset、性能恆定、天然防重複/漏數據。劣勢:不支援任意跳頁。
結語
LIMIT 是 MySQL 分頁利器,但 **大 Offset = 性能殺手**。工程選型:首頁/前幾頁 → LIMIT+覆蓋索引;無限滾動/深分頁 → Keyset Pagination;跳頁需求 → 延遲關聯/緩存/搜索引擎。始終用 EXPLAIN 驗證執行計劃,讓分頁在百萬級表上依然毫秒級返回。
- 上一篇文章: SQL Server 到 MySQL 數據遷移:DTS 導出文本 + LOAD DATA 免代碼實戰
- 下一篇文章: Windows 下 MySQL UDF 開發全流程:從 VC++ 編譯到 CREATE FUNCTION 部署
Copyright ©
程式碼之家 All Rights Reserved