SELECT * FROM t ORDER BY id LIMIT 980000, 10;
MySQL 需掃描 980,010 行,丟棄前 980,000 行,**時間複雜度 O(N)**,偏移量越大越慢。
-- 1. 子查詢先取 ID(覆蓋索引,極快)
SELECT id FROM t ORDER BY id LIMIT 980000, 1;
-- 2. 主查詢回表僅 10 行
SELECT * FROM t
WHERE id >= (SELECT id FROM t ORDER BY id LIMIT 980000, 1)
ORDER BY id LIMIT 10;
SELECT t.*
FROM t
INNER JOIN (
SELECT id FROM t ORDER BY id LIMIT 980000, 1
) AS tmp USING (id)
ORDER BY t.id LIMIT 10;
| 偏移量 | 原始 LIMIT | 優化後 | 提升 |
|---|---|---|---|
| 10,000 | 0.12s | 0.002s | 60x |
| 100,000 | 0.85s | 0.003s | 280x |
| 1,000,000 | 8.2s | 0.004s | 2000x+ |
-- 錯誤:子查詢無 WHERE
SELECT * FROM t WHERE status=1 AND id >= (SELECT id FROM t ORDER BY id LIMIT 980000, 1) LIMIT 10;
-- 正確:子查詢帶相同 WHERE
SELECT * FROM t
WHERE status=1
AND id >= (
SELECT id FROM t WHERE status=1 ORDER BY id LIMIT 980000, 1
)
ORDER BY id LIMIT 10;
-- 客戶端記住上一頁最大 ID
SELECT * FROM t WHERE id > 980000 ORDER BY id LIMIT 10;
EXPLAIN 看 Using indexFORCE INDEX (PRIMARY) 防止優化器誤選全表掃描