表 t1 約 99 萬行,主鍵 id,字段 ftype 為 tinyint。典型分頁 SQL:
SELECT * FROM t1 WHERE ftype=1 ORDER BY id DESC LIMIT 100, 10; -- 淺分頁 SELECT * FROM t1 WHERE ftype=1 ORDER BY id DESC LIMIT 935500, 10; -- 深分頁
| SQL | type | key | rows(掃描行數) | Extra | 耗時 |
|---|---|---|---|---|---|
| 淺分頁 LIMIT 500,10 | index | PRIMARY | 510 | Using where | 0.05s |
| 深分頁 LIMIT 935500,10 | index | PRIMARY | 935,510 | Using where | 2.39s |
深分頁掃描行數是淺分頁的 1800 倍,耗時卻是 48 倍,說明大量 CPU 消耗在「跳過行」邏輯上。
SELECT * FROM (
SELECT * FROM t1
WHERE id > (SELECT id FROM t1 WHERE ftype=1 ORDER BY id DESC LIMIT 935510, 1)
LIMIT 10
) t ORDER BY id DESC;
執行計劃亮點:最內層子查詢 type=index, rows=935511, Extra=Using where(僅掃描索引),外層 rows=10。實測 **1.86s,提升 28.2%**。
SELECT * FROM t1
INNER JOIN (
SELECT id FROM t1 WHERE ftype=1 ORDER BY id DESC LIMIT 935500, 10
) t2 USING (id);
執行計劃亮點:Derived 表 rows=935510 僅讀索引,主查詢 type=eq_ref, rows=1 精準回表。實測 **1.83s,提升 30.8%**。
| 方案 | 原始耗時 | 優化耗時 | 提升比例 |
|---|---|---|---|
| 子查詢 | 2.22s | 2.01s | 10.6% |
| INNER JOIN | 2.22s | 1.70s | 30.2% |
| 場景 | 子查詢提升 | INNER JOIN 提升 | 推薦 |
|---|---|---|---|
| 大分頁 + WHERE | 28.2% | 30.8% | INNER JOIN |
| 大分頁無 WHERE | 10.6% | 30.2% | INNER JOIN |
| 小分頁 + WHERE | 24.9% | 156.5% | INNER JOIN |
| 小分頁無 WHERE | 554.4% | 11.7% | 子查詢 |
| 總體平均 | 154.5% | 57.3% | INNER JOIN |
eq_ref 主鍵查找,無 filesort。/*+ MAX_EXECUTION_TIME(1000) */ 等 Hint 精準控制。USING (id) 明確表達「按主鍵關聯」,減少優化器誤判概率。-- 標準分頁模板(帶業務過濾)
SELECT t.*
FROM biz_table t
INNER JOIN (
SELECT id FROM biz_table
WHERE status=1 AND tenant_id=100 -- 業務過濾下推到索引掃描層
ORDER BY id DESC LIMIT ?, ?
) tmp USING (id)
ORDER BY t.id DESC; -- 保證最終輸出順序
通過 INNER JOIN + 覆蓋索引子查詢 重寫分頁,實現「索引定位主鍵 → 主鍵精準回表」模式。實測大分頁提升 30%+,小分頁提升 150%+,**建議作為團隊分頁 SQL 強制規範**。對於無條件主鍵序分頁,優先採用 id > last_id 範圍查詢獲取極致性能。