LIMIT 100000, 10 需掃描前 10 萬行再丟棄,耗時隨 OFFSET 線性增長。
| 方案 | SQL 範例 | OFFSET=10 耗時 | OFFSET=90000 耗時 |
|---|---|---|---|
| 原生 LIMIT | SELECT * FROM t LIMIT 90000,10 | 0.0005s | 8-9s |
| 子查詢定位 ID | SELECT * FROM t WHERE id >= (SELECT id FROM t ORDER BY id LIMIT 90000,1) LIMIT 10 | 0.0006s | 0.006s (1/3) |
| 複合索引 + 子查詢 | INDEX(vtype, id) + 子查詢 | 0.04s | 0.04s |
| IN 子句二次查詢 | 先查 ID 字串,再 WHERE id IN (...) | 極快 | 極快 |
SELECT * FROM `table`
WHERE id >= (SELECT id FROM `table` ORDER BY id LIMIT 90000, 1)
LIMIT 10;
利用主鍵索引快速定位,避免掃描大量非目標行。
-- 針對 WHERE vtype=1 ORDER BY id LIMIT 90000,10
ALTER TABLE `collect` ADD INDEX idx_vtype_id (vtype, id);
-- 必須只 SELECT 主鍵才能用到覆蓋索引
SELECT id FROM `collect` WHERE vtype=1 ORDER BY id LIMIT 90000,10; -- 0.04s
-- 加上 title 即失效回表,退化為 8-9s
-- 步驟1:高效取得目標頁 ID 字串 "90001,90002,..."
SELECT id FROM `collect` WHERE vtype=1 ORDER BY id LIMIT 90000,10;
-- 步驟2:主鍵 IN 查詢極快
SELECT id,title,url FROM `collect` WHERE id IN (90001,90002,...);
$db->pagesize = 20;
$sql = "SELECT id FROM collect WHERE vtype=$vtype";
$db->execute($sql);
$strpage = $db->strpage(); // 產生分頁 HTML
$ids = [];
while ($rs = $db->fetch_array()) $ids[] = $rs['id'];
$id_str = implode(',', $ids);
$db->pagesize = 0; // 關閉分頁
$db->execute("SELECT id,title,url FROM collect WHERE id IN ($id_str)");
// 輸出結果...
INDEX(vtype, id) + IN 方案,90 萬 OFFSET 查詢穩定在 0.1-0.2 秒。SELECT *,只取必要欄位。