LIMIT 是分頁、取 Top-N 的核心語法,但大偏移量(如 LIMIT 1000000, 10)會導致全表掃描性能崩塌。本文覆蓋語法變體、偏移量陷阱、優化方案。
| 語法 | 含義 | 等價寫法 |
|---|---|---|
LIMIT 5 | 前 5 行 | LIMIT 0, 5 |
LIMIT 5, 10 | 第 6~15 行(偏移 5,取 10) | LIMIT 10 OFFSET 5 |
LIMIT 95, -1 | 第 96 行到末尾 | MySQL 專有,-1 表示無上限 |
注意: 偏移量從 0 開始,LIMIT 0, 10 取前 10 行。
LIMIT 10 OFFSET 5 -- 等同 LIMIT 5, 10
-- 百萬偏移:MySQL 需掃描前 1,000,000 行再丟棄,極慢
SELECT * FROM huge_table LIMIT 1000000, 10;
原理: InnoDB 需按主鍵順序讀取並丟棄前 N 行,IO 與 CPU 雙重浪費。
| 方案 | 適用場景 | 核心思路 |
|---|---|---|
| 延遲關聯 | 單表、有主鍵 | SELECT * FROM t JOIN (SELECT id FROM t LIMIT 1000000, 10) tmp USING(id) 只掃描主鍵索引 |
| 游標/Keyset 分頁 | 翻頁、無需跳頁 | WHERE id > last_seen_id ORDER BY id LIMIT 10 利用索引範圍查詢 |
| 覆蓋索引 | 只查索引列 | 索引包含所有 SELECT 列,避免回表 |
| 預計算/緩存 | 熱門首頁 | Redis 緩存首頁數據,翻頁走 DB |
LIMIT offset, rows 可接受(低頻、用戶耐心高)。last_id 或 cursor。page/size 直接拼 SQL,必須在服務端轉換為 Keyset 或限制最大頁碼(如 ≤ 1000)。