根據偏移量大小選擇策略:
LIMIT offset, n 最快WHERE id >= (SELECT id ... LIMIT offset, 1) 顯著優於直接 LIMIT| 查詢方式 | Offset=10 | Offset=10,000 |
|---|---|---|
SELECT * FROM user LIMIT offset, 10 | 0.0004~0.0005s | 0.0187s |
SELECT * FROM user WHERE uid >= (SELECT uid FROM user ORDER BY uid LIMIT offset, 1) LIMIT 10 | 0.0005~0.0006s | 0.0061s (3x 快) |
SELECT uid ... LIMIT offset, 1 僅遍歷聚簇索引葉子節點 (極窄),定位目標主鍵值;外層 WHERE uid >= target 直接範圍查找,僅回表 LIMIT n 行-- 通用分頁存儲過程
CREATE PROCEDURE page_query(
IN p_table VARCHAR(64),
IN p_where VARCHAR(500),
IN p_order VARCHAR(100),
IN p_offset INT,
IN p_limit INT,
IN p_pk VARCHAR(64) -- 主鍵列名
)
BEGIN
IF p_offset < 1000 THEN
SET @sql = CONCAT('SELECT * FROM ', p_table, ' ', p_where, ' ORDER BY ', p_order, ' LIMIT ', p_offset, ', ', p_limit);
ELSE
SET @sql = CONCAT(
'SELECT * FROM ', p_table, ' ',
'WHERE ', p_pk, ' >= (SELECT ', p_pk, ' FROM ', p_table, ' ', p_where, ' ORDER BY ', p_order, ' LIMIT ', p_offset, ', 1) ',
p_where, ' ORDER BY ', p_order, ' LIMIT ', p_limit
);
END IF;
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
使用:CALL page_query('user', 'WHERE status=1', 'uid', 50000, 20, 'uid');
ORDER BY 列必須有索引,否則子查詢同樣慢>= 而非 >= 配合 LIMIT 1)WHERE 子查詢與主查詢必須完全一致,否則結果集偏移